diff --git a/.gitignore b/.gitignore index 0af37a1..1f663d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ binaries build Makefile +CMakeLists.txt.user +*.cbp diff --git a/Levels/Geometry/Block.obj b/Levels/Geometry/Block.obj new file mode 100644 index 0000000..1af1602 --- /dev/null +++ b/Levels/Geometry/Block.obj @@ -0,0 +1,720 @@ +# Blender v2.71 (sub 0) OBJ File: 'ruins_block.blend' +# www.blender.org +o Block_Cube +v -1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +v -1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +v 1.000000 -0.973911 -0.973911 +v 0.973911 -1.000000 -1.000000 +v 0.973911 -1.000000 -1.000000 +v 0.999735 -0.977624 -0.975900 +v 0.998943 -0.981261 -0.978115 +v 0.997642 -0.984749 -0.980509 +v 0.995859 -0.988016 -0.983034 +v 0.993628 -0.990996 -0.985640 +v 0.990996 -0.993628 -0.988272 +v 0.988016 -0.995859 -0.990877 +v 0.984749 -0.997642 -0.993402 +v 0.981261 -0.998943 -0.995797 +v 0.977624 -0.999735 -0.998011 +v 0.977624 -0.998011 -0.999734 +v 0.981261 -0.995797 -0.998943 +v 0.984749 -0.993402 -0.997642 +v 0.988016 -0.990877 -0.995858 +v 0.990996 -0.988272 -0.993628 +v 0.993628 -0.985640 -0.990996 +v 0.995859 -0.983034 -0.988016 +v 0.997642 -0.980509 -0.984749 +v 0.998943 -0.978115 -0.981261 +v 0.999735 -0.975900 -0.977624 +v 0.973911 -1.000000 1.000000 +v 1.000000 -0.973911 0.973911 +v 0.973911 -1.000000 1.000000 +v 0.977624 -0.999735 0.998011 +v 0.981261 -0.998943 0.995797 +v 0.984749 -0.997642 0.993402 +v 0.988016 -0.995859 0.990877 +v 0.990996 -0.993628 0.988272 +v 0.993628 -0.990996 0.985640 +v 0.995859 -0.988016 0.983034 +v 0.997642 -0.984749 0.980509 +v 0.998943 -0.981261 0.978115 +v 0.999735 -0.977624 0.975900 +v 0.999735 -0.975900 0.977624 +v 0.998943 -0.978115 0.981261 +v 0.997642 -0.980509 0.984749 +v 0.995859 -0.983034 0.988016 +v 0.993628 -0.985640 0.990996 +v 0.990996 -0.988272 0.993628 +v 0.988016 -0.990877 0.995859 +v 0.984749 -0.993402 0.997642 +v 0.981261 -0.995797 0.998943 +v 0.977624 -0.998011 0.999735 +v 1.000000 0.973911 -0.973911 +v 0.973912 1.000000 -0.999999 +v 0.973912 1.000000 -0.999999 +v 0.999735 0.975900 -0.977623 +v 0.998944 0.978115 -0.981261 +v 0.997643 0.980509 -0.984748 +v 0.995859 0.983034 -0.988015 +v 0.993628 0.985640 -0.990995 +v 0.990996 0.988272 -0.993627 +v 0.988016 0.990877 -0.995858 +v 0.984749 0.993402 -0.997642 +v 0.981262 0.995797 -0.998943 +v 0.977625 0.998011 -0.999734 +v 0.977625 0.999735 -0.998010 +v 0.981262 0.998943 -0.995796 +v 0.984749 0.997642 -0.993402 +v 0.988016 0.995859 -0.990876 +v 0.990996 0.993628 -0.988271 +v 0.993628 0.990996 -0.985639 +v 0.995859 0.988016 -0.983034 +v 0.997643 0.984749 -0.980508 +v 0.998944 0.981261 -0.978114 +v 0.999735 0.977624 -0.975900 +v 0.973911 1.000000 1.000001 +v 0.999999 0.973911 0.973912 +v 0.973911 1.000000 1.000001 +v 0.977623 0.998011 0.999735 +v 0.981261 0.995797 0.998944 +v 0.984748 0.993402 0.997643 +v 0.988015 0.990877 0.995859 +v 0.990995 0.988272 0.993628 +v 0.993627 0.985640 0.990996 +v 0.995858 0.983034 0.988017 +v 0.997642 0.980509 0.984750 +v 0.998942 0.978115 0.981262 +v 0.999734 0.975900 0.977625 +v 0.999734 0.977624 0.975901 +v 0.998942 0.981261 0.978115 +v 0.997642 0.984749 0.980510 +v 0.995858 0.988016 0.983035 +v 0.993627 0.990996 0.985640 +v 0.990995 0.993628 0.988272 +v 0.988015 0.995859 0.990878 +v 0.984748 0.997642 0.993403 +v 0.981261 0.998943 0.995797 +v 0.977623 0.999735 0.998011 +v -2.999704 -0.973911 0.973911 +v -2.973616 -1.000000 0.999999 +v -2.973616 -1.000000 0.999999 +v -2.999439 -0.977624 0.975900 +v -2.998648 -0.981262 0.978114 +v -2.997347 -0.984749 0.980508 +v -2.995563 -0.988016 0.983034 +v -2.993332 -0.990996 0.985639 +v -2.990700 -0.993628 0.988271 +v -2.987720 -0.995859 0.990876 +v -2.984453 -0.997643 0.993402 +v -2.980966 -0.998944 0.995796 +v -2.977329 -0.999735 0.998010 +v -2.977329 -0.998011 0.999734 +v -2.980966 -0.995797 0.998943 +v -2.984453 -0.993403 0.997642 +v -2.987720 -0.990877 0.995858 +v -2.990700 -0.988272 0.993627 +v -2.993332 -0.985640 0.990995 +v -2.995563 -0.983035 0.988015 +v -2.997347 -0.980509 0.984748 +v -2.998648 -0.978115 0.981261 +v -2.999439 -0.975901 0.977624 +v -2.973615 -1.000000 -1.000001 +v -2.999704 -0.973911 -0.973912 +v -2.973615 -1.000000 -1.000001 +v -2.977328 -0.999735 -0.998012 +v -2.980965 -0.998944 -0.995798 +v -2.984453 -0.997643 -0.993403 +v -2.987720 -0.995859 -0.990878 +v -2.990700 -0.993628 -0.988273 +v -2.993332 -0.990996 -0.985640 +v -2.995562 -0.988016 -0.983035 +v -2.997346 -0.984749 -0.980510 +v -2.998647 -0.981262 -0.978115 +v -2.999438 -0.977624 -0.975901 +v -2.999438 -0.975901 -0.977625 +v -2.998647 -0.978115 -0.981262 +v -2.997346 -0.980509 -0.984750 +v -2.995562 -0.983035 -0.988017 +v -2.993332 -0.985640 -0.990997 +v -2.990700 -0.988272 -0.993629 +v -2.987720 -0.990877 -0.995859 +v -2.984453 -0.993403 -0.997643 +v -2.980965 -0.995797 -0.998944 +v -2.977328 -0.998011 -0.999735 +v -2.999705 0.973911 0.973910 +v -2.973616 1.000000 0.999999 +v -2.973616 1.000000 0.999999 +v -2.999439 0.975900 0.977623 +v -2.998648 0.978114 0.981260 +v -2.997347 0.980509 0.984748 +v -2.995563 0.983034 0.988015 +v -2.993333 0.985639 0.990995 +v -2.990700 0.988271 0.993627 +v -2.987721 0.990877 0.995858 +v -2.984454 0.993402 0.997642 +v -2.980966 0.995796 0.998942 +v -2.977329 0.998011 0.999734 +v -2.977329 0.999734 0.998010 +v -2.980966 0.998943 0.995796 +v -2.984454 0.997642 0.993402 +v -2.987721 0.995858 0.990876 +v -2.990700 0.993628 0.988271 +v -2.993333 0.990996 0.985639 +v -2.995563 0.988016 0.983034 +v -2.997347 0.984749 0.980508 +v -2.998648 0.981261 0.978114 +v -2.999439 0.977624 0.975900 +v -2.973616 1.000000 -1.000000 +v -2.999704 0.973911 -0.973912 +v -2.973616 1.000000 -1.000000 +v -2.977329 0.998011 -0.999735 +v -2.980966 0.995796 -0.998944 +v -2.984453 0.993402 -0.997643 +v -2.987720 0.990877 -0.995859 +v -2.990700 0.988271 -0.993628 +v -2.993332 0.985639 -0.990996 +v -2.995563 0.983034 -0.988016 +v -2.997347 0.980509 -0.984749 +v -2.998648 0.978114 -0.981262 +v -2.999439 0.975900 -0.977625 +v -2.999439 0.977624 -0.975901 +v -2.998648 0.981261 -0.978115 +v -2.997347 0.984749 -0.980509 +v -2.995563 0.988016 -0.983035 +v -2.993332 0.990996 -0.985640 +v -2.990700 0.993628 -0.988272 +v -2.987720 0.995858 -0.990877 +v -2.984453 0.997642 -0.993403 +v -2.980966 0.998943 -0.995797 +v -2.977329 0.999734 -0.998011 +vt 0.839733 0.000000 +vt 0.848833 0.013044 +vt -0.537296 -0.000000 +vt -0.546397 0.013044 +vt 0.151167 0.000000 +vt 0.839733 0.013044 +vt 0.839733 0.986956 +vt 0.160267 0.986956 +vt 0.160267 0.013044 +vt 0.848833 0.000000 +vt 0.160370 0.000000 +vt 0.151270 0.013045 +vt 1.537399 0.000000 +vt 1.546500 0.013044 +vt 0.974265 0.996942 +vt -0.001961 0.996942 +vt -0.001961 -0.003057 +vt 0.974264 -0.003058 +vt 0.848834 -0.013044 +vt -0.546397 -0.013044 +vt -0.537296 -1.000000 +vt 0.839733 -1.000000 +vt 0.947629 -0.000000 +vt 0.003341 -0.000000 +vt 0.003341 1.000000 +vt 0.947629 1.000000 +vt 0.839732 1.000000 +vt -0.537296 1.000000 +vt 0.151167 1.000000 +vt 0.841028 0.000995 +vt 0.841028 0.000133 +vt 0.842297 0.002102 +vt 0.842297 0.000528 +vt 0.848011 0.003299 +vt 0.846532 0.001179 +vt 0.847367 0.000528 +vt 0.848465 0.002102 +vt 0.847389 0.004562 +vt 0.845651 0.002071 +vt 0.846610 0.005864 +vt 0.844742 0.003186 +vt 0.845692 0.007180 +vt 0.843824 0.004502 +vt 0.844653 0.008483 +vt 0.842915 0.005992 +vt 0.843513 0.009746 +vt 0.842034 0.007626 +vt 0.842297 0.010943 +vt 0.841199 0.009369 +vt 0.840427 0.011188 +vt 0.841028 0.012050 +vt 0.158972 0.012050 +vt 0.159573 0.011188 +vt 0.157703 0.010943 +vt 0.158801 0.009369 +vt 0.156487 0.009746 +vt 0.157966 0.007626 +vt 0.155347 0.008483 +vt 0.157085 0.005992 +vt 0.154308 0.007180 +vt 0.156176 0.004502 +vt 0.153389 0.005864 +vt 0.155258 0.003186 +vt 0.152611 0.004562 +vt 0.154349 0.002071 +vt 0.151989 0.003299 +vt 0.153468 0.001179 +vt 0.151535 0.002102 +vt 0.152633 0.000528 +vt 0.841028 0.999867 +vt 0.841028 0.999005 +vt 0.842297 0.999472 +vt 0.842297 0.997898 +vt 0.846532 0.998821 +vt 0.848011 0.996701 +vt 0.848464 0.997898 +vt 0.847367 0.999472 +vt 0.845651 0.997929 +vt 0.847388 0.995438 +vt 0.844742 0.996814 +vt 0.846610 0.994136 +vt 0.843824 0.995498 +vt 0.845692 0.992820 +vt 0.842915 0.994008 +vt 0.844653 0.991517 +vt 0.842034 0.992374 +vt 0.843513 0.990254 +vt 0.841199 0.990631 +vt 0.842296 0.989057 +vt 0.841028 0.987950 +vt 0.840426 0.988812 +vt 0.159573 0.988812 +vt 0.158972 0.987950 +vt 0.158801 0.990631 +vt 0.157703 0.989057 +vt 0.157966 0.992374 +vt 0.156487 0.990254 +vt 0.157085 0.994008 +vt 0.155347 0.991517 +vt 0.156176 0.995498 +vt 0.154307 0.992820 +vt 0.155258 0.996814 +vt 0.153389 0.994136 +vt 0.154349 0.997929 +vt 0.152611 0.995438 +vt 0.153468 0.998821 +vt 0.151989 0.996701 +vt 0.152633 0.999472 +vt 0.151535 0.997898 +vt 0.841028 1.000132 +vt 0.841028 1.000994 +vt 0.159075 0.000133 +vt 0.159075 0.000995 +vt 0.157807 0.000529 +vt 0.157807 0.002102 +vt 0.159075 0.999006 +vt 0.157807 0.997899 +vt 0.157807 0.999472 +vt 0.159075 0.999868 +vt 0.159075 -0.000994 +vt 0.159075 -0.000132 +vt 0.160370 1.000000 +vt 0.846610 0.992820 +vt 0.846610 0.007180 +vt 0.845692 0.005864 +vt 0.845692 0.994136 +vt 0.844653 0.004562 +vt 0.844653 0.995438 +vt 0.843513 0.003299 +vt 0.843513 0.996701 +vt 0.153493 0.007180 +vt 0.153493 0.992820 +vt 0.154411 0.994136 +vt 0.154411 0.005864 +vt 0.155450 0.995439 +vt 0.155450 0.004562 +vt 0.156590 0.996702 +vt 0.156590 0.003299 +vt 0.160370 2.000000 +vt 0.159075 1.999005 +vt 0.159075 1.000994 +vt 0.927508 0.000000 +vt 0.003734 0.000000 +vt 0.003734 1.000000 +vt 0.927508 1.000000 +vn 0.000000 0.167500 -0.985900 +vn 1.000000 0.000000 0.000000 +vn 0.000000 -0.447200 0.894400 +vn -0.000000 1.000000 0.000000 +vn -1.000000 -0.000000 -0.000000 +vn 0.000000 0.911700 0.410900 +vn 0.000000 -0.440200 -0.897900 +vn -0.000000 -0.000000 1.000000 +vn -0.000000 -0.122600 0.992500 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.549700 -0.835400 +vn 0.000000 -0.911800 -0.410700 +vn 0.394600 -0.649700 -0.649800 +vn 0.504500 -0.610500 -0.610500 +vn 0.599600 -0.565900 -0.565900 +vn 0.682100 -0.517100 -0.517100 +vn 0.753900 -0.464500 -0.464600 +vn 0.816500 -0.408300 -0.408300 +vn 0.870700 -0.347700 -0.347800 +vn 0.916800 -0.282400 -0.282400 +vn 0.954400 -0.211100 -0.211100 +vn 0.982200 -0.132800 -0.132800 +vn 0.997800 -0.046400 -0.046500 +vn 0.997800 -0.046400 0.046500 +vn 0.982200 -0.132800 0.132800 +vn 0.954400 -0.211100 0.211100 +vn 0.916800 -0.282400 0.282400 +vn 0.870700 -0.347700 0.347700 +vn 0.816500 -0.408200 0.408200 +vn 0.753900 -0.464600 0.464600 +vn 0.682100 -0.517100 0.517100 +vn 0.599600 -0.565900 0.565900 +vn 0.504500 -0.610500 0.610500 +vn 0.394600 -0.649800 0.649700 +vn 0.394600 0.649700 -0.649700 +vn 0.504500 0.610500 -0.610500 +vn 0.599600 0.565900 -0.565900 +vn 0.682100 0.517100 -0.517100 +vn 0.753900 0.464600 -0.464600 +vn 0.816500 0.408300 -0.408300 +vn 0.870700 0.347700 -0.347800 +vn 0.916800 0.282300 -0.282400 +vn 0.954400 0.211100 -0.211100 +vn 0.982200 0.132800 -0.132800 +vn 0.997800 0.046400 -0.046500 +vn 0.997800 0.046500 0.046500 +vn 0.982200 0.132800 0.132800 +vn 0.954400 0.211100 0.211100 +vn 0.916800 0.282400 0.282400 +vn 0.870700 0.347800 0.347800 +vn 0.816500 0.408200 0.408300 +vn 0.753900 0.464600 0.464600 +vn 0.682100 0.517100 0.517100 +vn 0.599600 0.565900 0.565900 +vn 0.504500 0.610500 0.610500 +vn 0.394600 0.649700 0.649700 +vn -0.394600 -0.649800 0.649700 +vn -0.504500 -0.610500 0.610500 +vn -0.599600 -0.565900 0.565900 +vn -0.682100 -0.517100 0.517100 +vn -0.753900 -0.464500 0.464500 +vn -0.816500 -0.408300 0.408300 +vn -0.870700 -0.347700 0.347800 +vn -0.916800 -0.282400 0.282400 +vn -0.954400 -0.211100 0.211100 +vn -0.982200 -0.132800 0.132800 +vn -0.997800 -0.046400 0.046500 +vn -0.997800 -0.046400 -0.046500 +vn -0.982200 -0.132800 -0.132800 +vn -0.954400 -0.211100 -0.211100 +vn -0.916800 -0.282400 -0.282400 +vn -0.870700 -0.347800 -0.347800 +vn -0.816500 -0.408300 -0.408300 +vn -0.753900 -0.464500 -0.464500 +vn -0.682100 -0.517100 -0.517100 +vn -0.599600 -0.565900 -0.565900 +vn -0.504500 -0.610500 -0.610500 +vn -0.394600 -0.649800 -0.649700 +vn -0.394600 0.649700 0.649800 +vn -0.504500 0.610500 0.610500 +vn -0.599600 0.565900 0.565900 +vn -0.682100 0.517100 0.517100 +vn -0.753900 0.464500 0.464600 +vn -0.816500 0.408300 0.408300 +vn -0.870700 0.347800 0.347800 +vn -0.916800 0.282300 0.282400 +vn -0.954400 0.211100 0.211100 +vn -0.982200 0.132800 0.132800 +vn -0.997800 0.046500 0.046500 +vn -0.997800 0.046500 -0.046500 +vn -0.982200 0.132800 -0.132800 +vn -0.954400 0.211100 -0.211100 +vn -0.916800 0.282400 -0.282400 +vn -0.870700 0.347800 -0.347800 +vn -0.816500 0.408200 -0.408300 +vn -0.753900 0.464500 -0.464500 +vn -0.682100 0.517100 -0.517100 +vn -0.599600 0.565900 -0.565900 +vn -0.504500 0.610500 -0.610500 +vn -0.394600 0.649800 -0.649700 +vn 0.997500 -0.071300 0.000000 +vn 0.977100 -0.212600 0.000000 +vn 0.936900 -0.349500 0.000000 +vn 0.877700 -0.479200 0.000000 +vn 0.800500 -0.599300 0.000000 +vn 0.707100 -0.707100 0.000000 +vn 0.599300 -0.800500 0.000000 +vn 0.479200 -0.877700 0.000000 +vn 0.349500 -0.937000 -0.000000 +vn 0.212600 -0.977100 0.000000 +vn 0.071300 -0.997500 0.000000 +vn 0.071400 0.000000 -0.997500 +vn 0.212600 0.000000 -0.977100 +vn 0.349500 0.000000 -0.937000 +vn 0.479300 0.000000 -0.877700 +vn 0.599300 0.000000 -0.800500 +vn 0.707100 -0.000000 -0.707100 +vn 0.800500 -0.000000 -0.599300 +vn 0.877700 -0.000000 -0.479200 +vn 0.936900 -0.000000 -0.349500 +vn 0.977100 -0.000000 -0.212600 +vn 0.997500 -0.000000 -0.071300 +vn 0.997500 0.000000 0.071300 +vn 0.977100 0.000000 0.212600 +vn 0.936900 0.000000 0.349500 +vn 0.877700 0.000000 0.479300 +vn 0.800500 0.000000 0.599300 +vn 0.707100 0.000000 0.707100 +vn 0.599300 -0.000000 0.800600 +vn 0.479300 -0.000000 0.877700 +vn 0.349500 -0.000000 0.936900 +vn 0.212600 -0.000000 0.977100 +vn 0.071300 -0.000000 0.997500 +vn 0.071300 0.997500 0.000000 +vn 0.212600 0.977100 0.000000 +vn 0.349500 0.937000 0.000000 +vn 0.479300 0.877700 0.000000 +vn 0.599300 0.800500 0.000000 +vn 0.707100 0.707100 0.000000 +vn 0.800500 0.599300 0.000000 +vn 0.877700 0.479200 0.000000 +vn 0.936900 0.349500 0.000000 +vn 0.977100 0.212600 0.000000 +vn 0.997500 0.071300 0.000000 +vn -0.997500 -0.071300 -0.000000 +vn -0.977200 -0.212500 -0.000000 +vn -0.937000 -0.349500 -0.000000 +vn -0.877700 -0.479300 -0.000000 +vn -0.800500 -0.599300 -0.000000 +vn -0.707100 -0.707200 -0.000000 +vn -0.599300 -0.800500 -0.000000 +vn -0.479200 -0.877700 -0.000000 +vn -0.349500 -0.936900 -0.000000 +vn -0.212600 -0.977100 -0.000000 +vn -0.071300 -0.997500 -0.000000 +vn -0.071300 0.000000 0.997500 +vn -0.212600 0.000000 0.977100 +vn -0.349500 0.000000 0.936900 +vn -0.479200 0.000000 0.877700 +vn -0.599300 0.000000 0.800500 +vn -0.707100 -0.000000 0.707100 +vn -0.800500 -0.000000 0.599300 +vn -0.877700 -0.000000 0.479300 +vn -0.936900 -0.000000 0.349500 +vn -0.977200 -0.000000 0.212500 +vn -0.997500 -0.000000 0.071400 +vn -0.997500 -0.000000 -0.071400 +vn -0.977200 -0.000000 -0.212500 +vn -0.937000 -0.000000 -0.349500 +vn -0.877700 -0.000000 -0.479300 +vn -0.800500 -0.000000 -0.599300 +vn -0.707100 -0.000000 -0.707100 +vn -0.599300 0.000000 -0.800500 +vn -0.479200 0.000000 -0.877700 +vn -0.349500 0.000000 -0.936900 +vn -0.212600 0.000000 -0.977100 +vn -0.071300 0.000000 -0.997500 +vn -0.071300 0.997500 -0.000000 +vn -0.212600 0.977100 -0.000000 +vn -0.349500 0.936900 -0.000000 +vn -0.479300 0.877700 -0.000000 +vn -0.599300 0.800600 -0.000000 +vn -0.707100 0.707200 -0.000000 +vn -0.800500 0.599300 -0.000000 +vn -0.877700 0.479300 -0.000000 +vn -0.936900 0.349500 -0.000000 +vn -0.977200 0.212500 -0.000000 +vn -0.997500 0.071300 -0.000000 +vn 0.000000 -1.000000 0.000000 +s off +f 10/1/1 9/2/1 11/1/1 126/3/1 125/4/1 124/3/1 6/5/1 2/5/1 +f 9/6/2 55/7/2 79/8/2 33/9/2 +f 1/10/3 5/10/3 102/11/3 101/12/3 103/11/3 34/13/3 33/14/3 32/13/3 +f 57/15/4 172/16/4 149/17/4 80/18/4 +f 101/9/5 147/8/5 171/7/5 125/6/5 +f 3/10/6 7/10/6 148/11/6 147/12/6 149/11/6 80/13/6 79/14/6 78/13/6 +f 56/1/7 55/19/7 57/1/7 172/3/7 171/20/7 170/3/7 8/5/7 4/5/7 +f 78/1/8 80/1/8 149/3/8 148/3/8 103/21/8 34/22/8 +f 2/5/9 6/5/9 124/3/9 126/3/9 11/1/9 10/1/9 +f 11/23/10 126/24/10 170/25/10 172/25/10 57/26/10 56/26/10 +f 4/5/4 8/5/4 170/3/4 172/3/4 57/1/4 56/1/4 +f 32/1/11 34/1/11 103/3/11 102/3/11 5/5/11 1/5/11 +f 78/27/12 80/27/12 149/28/12 148/28/12 7/29/12 3/29/12 +f 22/30/13 21/31/13 10/1/13 11/1/13 +f 23/32/14 20/33/14 21/31/14 22/30/14 +f 24/34/15 19/35/15 20/36/15 23/37/15 +f 25/38/16 18/39/16 19/35/16 24/34/16 +f 26/40/17 17/41/17 18/39/17 25/38/17 +f 27/42/18 16/43/18 17/41/18 26/40/18 +f 28/44/19 15/45/19 16/43/19 27/42/19 +f 29/46/20 14/47/20 15/45/20 28/44/20 +f 30/48/21 13/49/21 14/47/21 29/46/21 +f 12/50/22 13/49/22 30/48/22 31/51/22 +f 9/6/23 12/50/23 31/51/23 +f 45/52/24 44/53/24 33/9/24 +f 46/54/25 43/55/25 44/53/25 45/52/25 +f 47/56/26 42/57/26 43/55/26 46/54/26 +f 48/58/27 41/59/27 42/57/27 47/56/27 +f 49/60/28 40/61/28 41/59/28 48/58/28 +f 50/62/29 39/63/29 40/61/29 49/60/29 +f 51/64/30 38/65/30 39/63/30 50/62/30 +f 52/66/31 37/67/31 38/65/31 51/64/31 +f 53/68/32 36/69/32 37/67/32 52/66/32 +f 35/30/33 36/32/33 53/33/33 54/31/33 +f 32/1/34 35/30/34 54/31/34 34/1/34 +f 68/70/35 67/71/35 56/27/35 57/27/35 +f 69/72/36 66/73/36 67/71/36 68/70/36 +f 70/74/37 65/75/37 66/76/37 69/77/37 +f 71/78/38 64/79/38 65/75/38 70/74/38 +f 72/80/39 63/81/39 64/79/39 71/78/39 +f 73/82/40 62/83/40 63/81/40 72/80/40 +f 74/84/41 61/85/41 62/83/41 73/82/41 +f 75/86/42 60/87/42 61/85/42 74/84/42 +f 76/88/43 59/89/43 60/87/43 75/86/43 +f 58/90/44 59/89/44 76/88/44 77/91/44 +f 55/7/45 58/90/45 77/91/45 +f 91/92/46 90/93/46 79/8/46 +f 92/94/47 89/95/47 90/93/47 91/92/47 +f 93/96/48 88/97/48 89/95/48 92/94/48 +f 94/98/49 87/99/49 88/97/49 93/96/49 +f 95/100/50 86/101/50 87/99/50 94/98/50 +f 96/102/51 85/103/51 86/101/51 95/100/51 +f 97/104/52 84/105/52 85/103/52 96/102/52 +f 98/106/53 83/107/53 84/105/53 97/104/53 +f 99/108/54 82/109/54 83/107/54 98/106/54 +f 81/71/55 82/73/55 99/72/55 100/70/55 +f 78/27/56 81/110/56 100/111/56 80/27/56 +f 114/112/57 113/113/57 102/11/57 103/11/57 +f 115/114/58 112/115/58 113/113/58 114/112/58 +f 116/66/59 111/67/59 112/69/59 115/68/59 +f 117/64/60 110/65/60 111/67/60 116/66/60 +f 118/62/61 109/63/61 110/65/61 117/64/61 +f 119/60/62 108/61/62 109/63/62 118/62/62 +f 120/58/63 107/59/63 108/61/63 119/60/63 +f 121/56/64 106/57/64 107/59/64 120/58/64 +f 122/54/65 105/55/65 106/57/65 121/56/65 +f 104/53/66 105/55/66 122/54/66 123/52/66 +f 101/9/67 104/53/67 123/52/67 +f 137/51/68 136/50/68 125/6/68 +f 138/48/69 135/49/69 136/50/69 137/51/69 +f 139/46/70 134/47/70 135/49/70 138/48/70 +f 140/44/71 133/45/71 134/47/71 139/46/71 +f 141/42/72 132/43/72 133/45/72 140/44/72 +f 142/40/73 131/41/73 132/43/73 141/42/73 +f 143/38/74 130/39/74 131/41/74 142/40/74 +f 144/34/75 129/35/75 130/39/75 143/38/75 +f 145/37/76 128/36/76 129/35/76 144/34/76 +f 127/116/77 128/117/77 145/118/77 146/119/77 +f 124/11/78 127/120/78 146/121/78 126/11/78 +f 160/119/79 159/116/79 148/122/79 149/122/79 +f 161/118/80 158/117/80 159/116/80 160/119/80 +f 162/106/81 157/107/81 158/109/81 161/108/81 +f 163/104/82 156/105/82 157/107/82 162/106/82 +f 164/102/83 155/103/83 156/105/83 163/104/83 +f 165/100/84 154/101/84 155/103/84 164/102/84 +f 166/98/85 153/99/85 154/101/85 165/100/85 +f 167/96/86 152/97/86 153/99/86 166/98/86 +f 168/94/87 151/95/87 152/97/87 167/96/87 +f 150/93/88 151/95/88 168/94/88 169/92/88 +f 147/8/89 150/93/89 169/92/89 +f 183/91/90 182/90/90 171/7/90 +f 184/88/91 181/89/91 182/90/91 183/91/91 +f 185/86/92 180/87/92 181/89/92 184/88/92 +f 186/84/93 179/85/93 180/87/93 185/86/93 +f 187/82/94 178/83/94 179/85/94 186/84/94 +f 188/80/95 177/81/95 178/83/95 187/82/95 +f 189/78/96 176/79/96 177/81/96 188/80/96 +f 190/74/97 175/75/97 176/79/97 189/78/97 +f 191/77/98 174/76/98 175/75/98 190/74/98 +f 173/116/99 174/117/99 191/118/99 192/119/99 +f 170/11/100 173/121/100 192/120/100 172/11/100 +f 9/6/101 33/9/101 44/53/101 12/50/101 +f 12/50/102 44/53/102 43/55/102 13/49/102 +f 13/49/103 43/55/103 42/57/103 14/47/103 +f 14/47/104 42/57/104 41/59/104 15/45/104 +f 15/45/105 41/59/105 40/61/105 16/43/105 +f 16/123/106 40/124/106 39/125/106 17/126/106 +f 17/126/107 39/125/107 38/127/107 18/128/107 +f 18/128/108 38/127/108 37/129/108 19/130/108 +f 19/130/109 37/129/109 36/32/109 20/73/109 +f 20/73/110 36/32/110 35/30/110 21/71/110 +f 21/71/111 35/30/111 32/1/111 10/27/111 +f 11/1/112 56/27/112 67/71/112 22/30/112 +f 22/30/113 67/71/113 66/73/113 23/32/113 +f 23/32/114 66/73/114 65/130/114 24/129/114 +f 24/129/115 65/130/115 64/128/115 25/127/115 +f 25/127/116 64/128/116 63/126/116 26/125/116 +f 26/125/117 63/126/117 62/123/117 27/124/117 +f 27/42/118 62/83/118 61/85/118 28/44/118 +f 28/44/119 61/85/119 60/87/119 29/46/119 +f 29/46/120 60/87/120 59/89/120 30/48/120 +f 30/48/121 59/89/121 58/90/121 31/51/121 +f 31/51/122 58/90/122 55/7/122 9/6/122 +f 33/9/123 79/8/123 90/93/123 45/52/123 +f 45/52/124 90/93/124 89/95/124 46/54/124 +f 46/54/125 89/95/125 88/97/125 47/56/125 +f 47/56/126 88/97/126 87/99/126 48/58/126 +f 48/58/127 87/99/127 86/101/127 49/60/127 +f 49/124/128 86/123/128 85/126/128 50/125/128 +f 50/125/129 85/126/129 84/128/129 51/127/129 +f 51/127/130 84/128/130 83/130/130 52/129/130 +f 52/129/131 83/130/131 82/73/131 53/32/131 +f 53/32/132 82/73/132 81/71/132 54/30/132 +f 54/30/133 81/71/133 78/27/133 34/1/133 +f 57/27/134 80/1/134 100/30/134 68/71/134 +f 68/71/135 100/30/135 99/32/135 69/73/135 +f 69/73/136 99/32/136 98/129/136 70/130/136 +f 70/130/137 98/129/137 97/127/137 71/128/137 +f 71/128/138 97/127/138 96/125/138 72/126/138 +f 72/126/139 96/125/139 95/124/139 73/123/139 +f 73/82/140 95/100/140 94/98/140 74/84/140 +f 74/84/141 94/98/141 93/96/141 75/86/141 +f 75/86/142 93/96/142 92/94/142 76/88/142 +f 76/88/143 92/94/143 91/92/143 77/91/143 +f 77/91/144 91/92/144 79/8/144 55/7/144 +f 101/9/145 125/6/145 136/50/145 104/53/145 +f 104/53/146 136/50/146 135/49/146 105/55/146 +f 105/55/147 135/49/147 134/47/147 106/57/147 +f 106/57/148 134/47/148 133/45/148 107/59/148 +f 107/59/149 133/45/149 132/43/149 108/61/149 +f 108/131/150 132/132/150 131/133/150 109/134/150 +f 109/134/151 131/133/151 130/135/151 110/136/151 +f 110/136/152 130/135/152 129/137/152 111/138/152 +f 111/138/153 129/137/153 128/117/153 112/115/153 +f 112/115/154 128/117/154 127/116/154 113/113/154 +f 113/113/155 127/116/155 124/122/155 102/11/155 +f 103/122/156 148/139/156 159/140/156 114/141/156 +f 114/113/157 159/116/157 158/117/157 115/115/157 +f 115/115/158 158/117/158 157/137/158 116/138/158 +f 116/138/159 157/137/159 156/135/159 117/136/159 +f 117/136/160 156/135/160 155/133/160 118/134/160 +f 118/134/161 155/133/161 154/132/161 119/131/161 +f 119/60/162 154/101/162 153/99/162 120/58/162 +f 120/58/163 153/99/163 152/97/163 121/56/163 +f 121/56/164 152/97/164 151/95/164 122/54/164 +f 122/54/165 151/95/165 150/93/165 123/52/165 +f 123/52/166 150/93/166 147/8/166 101/9/166 +f 125/6/167 171/7/167 182/90/167 137/51/167 +f 137/51/168 182/90/168 181/89/168 138/48/168 +f 138/48/169 181/89/169 180/87/169 139/46/169 +f 139/46/170 180/87/170 179/85/170 140/44/170 +f 140/44/171 179/85/171 178/83/171 141/42/171 +f 141/131/172 178/132/172 177/133/172 142/134/172 +f 142/134/173 177/133/173 176/135/173 143/136/173 +f 143/136/174 176/135/174 175/137/174 144/138/174 +f 144/138/175 175/137/175 174/117/175 145/115/175 +f 145/115/176 174/117/176 173/116/176 146/113/176 +f 146/113/177 173/116/177 170/122/177 126/11/177 +f 149/11/178 172/122/178 192/116/178 160/113/178 +f 160/113/179 192/116/179 191/117/179 161/115/179 +f 161/115/180 191/117/180 190/137/180 162/138/180 +f 162/138/181 190/137/181 189/135/181 163/136/181 +f 163/136/182 189/135/182 188/133/182 164/134/182 +f 164/134/183 188/133/183 187/132/183 165/131/183 +f 165/100/184 187/82/184 186/84/184 166/98/184 +f 166/98/185 186/84/185 185/86/185 167/96/185 +f 167/96/186 185/86/186 184/88/186 168/94/186 +f 168/94/187 184/88/187 183/91/187 169/92/187 +f 169/92/188 183/91/188 171/7/188 147/8/188 +f 32/142/189 34/142/189 103/143/189 102/143/189 124/144/189 126/144/189 11/145/189 10/145/189 diff --git a/Geometry/Bunny.ab b/Levels/Geometry/Bunny.ab similarity index 100% rename from Geometry/Bunny.ab rename to Levels/Geometry/Bunny.ab diff --git a/Geometry/Bunny.obj b/Levels/Geometry/Bunny.obj similarity index 100% rename from Geometry/Bunny.obj rename to Levels/Geometry/Bunny.obj diff --git a/Geometry/BunnyColors.atb b/Levels/Geometry/BunnyColors.atb similarity index 100% rename from Geometry/BunnyColors.atb rename to Levels/Geometry/BunnyColors.atb diff --git a/Levels/Geometry/Column.obj b/Levels/Geometry/Column.obj new file mode 100644 index 0000000..30a0aa5 --- /dev/null +++ b/Levels/Geometry/Column.obj @@ -0,0 +1,936 @@ +# Blender v2.71 (sub 0) OBJ File: 'ruins_column.blend' +# www.blender.org +o Cube +v 0.366457 0.983043 -0.928802 +v 0.376163 1.000000 -0.908138 +v 0.397638 0.983043 -0.915886 +v 0.397638 -0.983043 -0.915886 +v 0.376163 -1.000000 -0.908138 +v 0.366457 -0.983043 -0.928802 +v 0.178215 0.983043 -0.982447 +v 0.191766 1.000000 -0.964074 +v 0.211317 0.983043 -0.975863 +v 0.211317 -0.983043 -0.975863 +v 0.191766 -1.000000 -0.964074 +v 0.178215 -0.983043 -0.982447 +v 0.016875 0.983043 -0.998338 +v -0.016875 0.983043 -0.998338 +v -0.000000 1.000000 -0.982961 +v -0.000000 -1.000000 -0.982961 +v -0.016875 -0.983043 -0.998338 +v 0.016875 -0.983043 -0.998338 +v 0.568678 -0.983043 -0.820712 +v 0.546104 -1.000000 -0.817302 +v 0.540616 -0.983043 -0.839463 +v 0.540616 0.983043 -0.839463 +v 0.546104 1.000000 -0.817302 +v 0.568678 0.983043 -0.820712 +v 0.717864 -0.983043 -0.693999 +v 0.695058 -1.000000 -0.695058 +v 0.693999 -0.983043 -0.717864 +v 0.693999 0.983043 -0.717864 +v 0.695058 1.000000 -0.695058 +v 0.717864 0.983043 -0.693999 +v 0.839463 -0.983043 -0.540616 +v 0.817302 -1.000000 -0.546104 +v 0.820712 -0.983043 -0.568678 +v 0.820712 0.983043 -0.568678 +v 0.817302 1.000000 -0.546104 +v 0.839463 0.983043 -0.540616 +v 0.928802 -0.983043 -0.366457 +v 0.908138 -1.000000 -0.376163 +v 0.915886 -0.983043 -0.397638 +v 0.915886 0.983043 -0.397638 +v 0.908138 1.000000 -0.376163 +v 0.928802 0.983043 -0.366457 +v 0.982447 -0.983043 -0.178215 +v 0.964074 -1.000000 -0.191766 +v 0.975863 -0.983043 -0.211317 +v 0.975863 0.983043 -0.211317 +v 0.964074 1.000000 -0.191766 +v 0.982447 0.983043 -0.178215 +v 0.998338 -0.983043 0.016875 +v 0.982961 -1.000000 -0.000000 +v 0.998338 -0.983043 -0.016875 +v 0.998338 0.983043 -0.016875 +v 0.982961 1.000000 -0.000000 +v 0.998338 0.983043 0.016875 +v 0.975863 -0.983043 0.211317 +v 0.964074 -1.000000 0.191766 +v 0.982447 -0.983043 0.178215 +v 0.982447 0.983043 0.178215 +v 0.964074 1.000000 0.191766 +v 0.975863 0.983043 0.211317 +v 0.915886 -0.983043 0.397638 +v 0.908138 -1.000000 0.376163 +v 0.928802 -0.983043 0.366457 +v 0.928802 0.983043 0.366457 +v 0.908138 1.000000 0.376163 +v 0.915886 0.983043 0.397638 +v 0.820712 -0.983043 0.568678 +v 0.817302 -1.000000 0.546104 +v 0.839463 -0.983043 0.540616 +v 0.839463 0.983043 0.540616 +v 0.817302 1.000000 0.546104 +v 0.820712 0.983043 0.568678 +v 0.693999 -0.983043 0.717864 +v 0.695058 -1.000000 0.695058 +v 0.717864 -0.983043 0.693999 +v 0.717864 0.983043 0.693999 +v 0.695058 1.000000 0.695058 +v 0.693999 0.983043 0.717864 +v 0.540616 -0.983043 0.839463 +v 0.546104 -1.000000 0.817302 +v 0.568678 -0.983043 0.820712 +v 0.568678 0.983043 0.820712 +v 0.546104 1.000000 0.817302 +v 0.540616 0.983043 0.839463 +v 0.366457 -0.983043 0.928802 +v 0.376163 -1.000000 0.908138 +v 0.397638 -0.983043 0.915886 +v 0.397638 0.983043 0.915886 +v 0.376163 1.000000 0.908138 +v 0.366457 0.983043 0.928802 +v 0.178215 -0.983043 0.982447 +v 0.191766 -1.000000 0.964074 +v 0.211317 -0.983043 0.975863 +v 0.211317 0.983043 0.975863 +v 0.191766 1.000000 0.964074 +v 0.178215 0.983043 0.982447 +v -0.016876 -0.983043 0.998338 +v -0.000000 -1.000000 0.982961 +v 0.016875 -0.983043 0.998338 +v 0.016875 0.983043 0.998338 +v -0.000000 1.000000 0.982961 +v -0.016876 0.983043 0.998338 +v -0.211317 -0.983043 0.975863 +v -0.191767 -1.000000 0.964074 +v -0.178216 -0.983043 0.982447 +v -0.178216 0.983043 0.982447 +v -0.191767 1.000000 0.964074 +v -0.211317 0.983043 0.975863 +v -0.397638 -0.983043 0.915886 +v -0.376163 -1.000000 0.908137 +v -0.366457 -0.983043 0.928802 +v -0.366457 0.983043 0.928802 +v -0.376163 1.000000 0.908137 +v -0.397638 0.983043 0.915886 +v -0.568679 -0.983043 0.820712 +v -0.546104 -1.000000 0.817302 +v -0.540616 -0.983043 0.839463 +v -0.540616 0.983043 0.839463 +v -0.546104 1.000000 0.817302 +v -0.568679 0.983043 0.820712 +v -0.717865 -0.983043 0.693999 +v -0.695059 -1.000000 0.695058 +v -0.693999 -0.983043 0.717864 +v -0.693999 0.983043 0.717864 +v -0.695059 1.000000 0.695058 +v -0.717865 0.983043 0.693999 +v -0.839463 -0.983043 0.540615 +v -0.817303 -1.000000 0.546103 +v -0.820713 -0.983043 0.568677 +v -0.820713 0.983043 0.568677 +v -0.817303 1.000000 0.546103 +v -0.839463 0.983043 0.540615 +v -0.928802 -0.983043 0.366456 +v -0.908138 -1.000000 0.376162 +v -0.915886 -0.983043 0.397637 +v -0.915886 0.983043 0.397637 +v -0.908138 1.000000 0.376162 +v -0.928802 0.983043 0.366456 +v -0.982448 -0.983043 0.178214 +v -0.964074 -1.000000 0.191765 +v -0.975863 -0.983043 0.211316 +v -0.975863 0.983043 0.211316 +v -0.964074 1.000000 0.191765 +v -0.982448 0.983043 0.178214 +v -0.998338 -0.983043 -0.016876 +v -0.982961 -1.000000 -0.000001 +v -0.998338 -0.983043 0.016874 +v -0.998338 0.983043 0.016874 +v -0.982961 1.000000 -0.000001 +v -0.998338 0.983043 -0.016876 +v -0.975863 -0.983043 -0.211318 +v -0.964074 -1.000000 -0.191767 +v -0.982447 -0.983043 -0.178216 +v -0.982447 0.983043 -0.178216 +v -0.964074 1.000000 -0.191767 +v -0.975863 0.983043 -0.211318 +v -0.915886 -0.983043 -0.397639 +v -0.908137 -1.000000 -0.376164 +v -0.928801 -0.983043 -0.366458 +v -0.928801 0.983043 -0.366458 +v -0.908137 1.000000 -0.376164 +v -0.915886 0.983043 -0.397639 +v -0.820712 -0.983043 -0.568679 +v -0.817302 -1.000000 -0.546105 +v -0.839462 -0.983043 -0.540617 +v -0.839462 0.983043 -0.540617 +v -0.817302 1.000000 -0.546105 +v -0.820712 0.983043 -0.568679 +v -0.693998 -0.983043 -0.717865 +v -0.695058 -1.000000 -0.695059 +v -0.717863 -0.983043 -0.694000 +v -0.717863 0.983043 -0.694000 +v -0.695058 1.000000 -0.695059 +v -0.693998 0.983043 -0.717865 +v -0.540614 -0.983043 -0.839464 +v -0.546103 -1.000000 -0.817303 +v -0.568677 -0.983043 -0.820713 +v -0.568677 0.983043 -0.820713 +v -0.546103 1.000000 -0.817303 +v -0.540614 0.983043 -0.839464 +v -0.366455 -0.983043 -0.928802 +v -0.376162 -1.000000 -0.908138 +v -0.397637 -0.983043 -0.915887 +v -0.397637 0.983043 -0.915887 +v -0.376162 1.000000 -0.908138 +v -0.366455 0.983043 -0.928802 +v -0.178214 -0.983043 -0.982448 +v -0.191765 -1.000000 -0.964074 +v -0.211316 -0.983043 -0.975863 +v -0.211316 0.983043 -0.975863 +v -0.191765 1.000000 -0.964074 +v -0.178214 0.983043 -0.982448 +vt 0.302972 0.503043 +vt 0.302972 0.995751 +vt 0.279010 0.995751 +vt 0.279010 0.503043 +vt 0.403686 0.503043 +vt 0.403686 0.995751 +vt 0.374867 0.995751 +vt 0.374867 0.503043 +vt 0.355657 0.225252 +vt 0.362339 0.177890 +vt 0.375448 0.133276 +vt 0.394479 0.093125 +vt 0.418700 0.058979 +vt 0.447181 0.032150 +vt 0.478828 0.013670 +vt 0.512424 0.004250 +vt 0.546679 0.004249 +vt 0.580275 0.013670 +vt 0.611922 0.032150 +vt 0.640403 0.058978 +vt 0.664625 0.093124 +vt 0.683655 0.133276 +vt 0.696764 0.177890 +vt 0.703447 0.225252 +vt 0.703447 0.273541 +vt 0.696764 0.320903 +vt 0.683656 0.365517 +vt 0.664625 0.405669 +vt 0.640404 0.439815 +vt 0.611922 0.466643 +vt 0.580275 0.485123 +vt 0.546679 0.494544 +vt 0.512425 0.494544 +vt 0.478829 0.485123 +vt 0.447182 0.466643 +vt 0.418700 0.439815 +vt 0.394479 0.405669 +vt 0.375448 0.365517 +vt 0.362339 0.320903 +vt 0.355657 0.273542 +vt 0.744031 0.503043 +vt 0.744031 0.995751 +vt 0.718615 0.995751 +vt 0.718615 0.503043 +vt 0.713072 0.503043 +vt 0.713072 0.995751 +vt 0.685493 0.995751 +vt 0.685493 0.503043 +vt 0.679609 0.503043 +vt 0.679609 0.995751 +vt 0.650928 0.995751 +vt 0.650928 0.503043 +vt 0.644929 0.503043 +vt 0.644929 0.995751 +vt 0.616248 0.995751 +vt 0.616248 0.503043 +vt 0.610364 0.503043 +vt 0.610364 0.995751 +vt 0.582785 0.995751 +vt 0.582785 0.503043 +vt 0.577242 0.503043 +vt 0.577242 0.995751 +vt 0.551826 0.995751 +vt 0.551826 0.503043 +vt 0.546837 0.503043 +vt 0.546837 0.995751 +vt 0.524560 0.995751 +vt 0.524560 0.503043 +vt 0.995012 0.503043 +vt 0.995012 0.995750 +vt 0.969595 0.995750 +vt 0.969595 0.503043 +vt 0.964052 0.503043 +vt 0.964052 0.995751 +vt 0.936474 0.995751 +vt 0.936474 0.503043 +vt 0.930589 0.503043 +vt 0.930589 0.995750 +vt 0.901909 0.995751 +vt 0.901909 0.503043 +vt 0.895909 0.503043 +vt 0.895909 0.995750 +vt 0.867228 0.995750 +vt 0.867228 0.503043 +vt 0.861344 0.503043 +vt 0.861344 0.995750 +vt 0.833765 0.995750 +vt 0.833766 0.503043 +vt 0.828223 0.503043 +vt 0.828223 0.995751 +vt 0.802806 0.995751 +vt 0.802806 0.503043 +vt 0.797818 0.503043 +vt 0.797818 0.995750 +vt 0.775540 0.995751 +vt 0.775540 0.503043 +vt 0.000000 0.995750 +vt 0.000000 0.503043 +vt 0.020378 0.503043 +vt 0.020378 0.995750 +vt 0.025016 0.995750 +vt 0.025016 0.503043 +vt 0.048979 0.503043 +vt 0.048979 0.995750 +vt 0.054270 0.995750 +vt 0.054270 0.503043 +vt 0.080896 0.503043 +vt 0.080896 0.995750 +vt 0.086637 0.995750 +vt 0.086637 0.503043 +vt 0.114903 0.503043 +vt 0.114903 0.995750 +vt 0.120873 0.995750 +vt 0.120873 0.503043 +vt 0.149693 0.503043 +vt 0.149693 0.995751 +vt 0.155663 0.995751 +vt 0.155664 0.503043 +vt 0.183929 0.503043 +vt 0.183929 0.995751 +vt 0.189670 0.995750 +vt 0.189670 0.503043 +vt 0.216296 0.503043 +vt 0.216296 0.995750 +vt 0.221587 0.995751 +vt 0.221587 0.503043 +vt 0.245550 0.503043 +vt 0.245550 0.995751 +vt 0.250188 0.995750 +vt 0.250188 0.503043 +vt 0.270566 0.503043 +vt 0.270566 0.995750 +vt 0.504181 0.995751 +vt 0.504181 0.503043 +vt 0.499543 0.503043 +vt 0.499543 0.995751 +vt 0.475581 0.995751 +vt 0.475581 0.503043 +vt 0.470290 0.503043 +vt 0.470290 0.995751 +vt 0.443664 0.995751 +vt 0.443664 0.503043 +vt 0.437923 0.503043 +vt 0.437923 0.995751 +vt 0.409657 0.995751 +vt 0.409657 0.503043 +vt 0.771297 0.503043 +vt 0.771297 0.995751 +vt 0.749020 0.995751 +vt 0.749020 0.503043 +vt 0.368896 0.503043 +vt 0.368896 0.995751 +vt 0.340631 0.995751 +vt 0.340631 0.503043 +vt 0.334889 0.503043 +vt 0.334889 0.995751 +vt 0.308264 0.995751 +vt 0.308264 0.503043 +vt 0.286588 0.445477 +vt 0.287173 0.439815 +vt 0.291226 0.440111 +vt 0.374451 0.127730 +vt 0.371623 0.135189 +vt 0.338553 1.000000 +vt 0.338553 0.498793 +vt 0.372150 1.000000 +vt 0.372150 0.498793 +vt 0.394269 0.087411 +vt 0.390463 0.093949 +vt 0.311604 0.411383 +vt 0.311394 0.405669 +vt 0.315410 0.404845 +vt 0.419285 0.053317 +vt 0.414647 0.058683 +vt 0.331421 0.371064 +vt 0.330425 0.365518 +vt 0.334250 0.363605 +vt 0.714797 0.498793 +vt 0.714797 1.000000 +vt 0.682018 0.498793 +vt 0.682018 1.000000 +vt 0.647928 0.498793 +vt 0.647928 1.000000 +vt 0.613839 0.498793 +vt 0.613839 1.000000 +vt 0.581060 0.498793 +vt 0.581060 1.000000 +vt 0.615856 0.030745 +vt 0.610565 0.026758 +vt 0.315410 0.093949 +vt 0.311394 0.093125 +vt 0.311604 0.087411 +vt 0.644456 0.058682 +vt 0.639818 0.053317 +vt 0.291226 0.058683 +vt 0.287173 0.058979 +vt 0.286588 0.053317 +vt 0.965778 0.498793 +vt 0.965778 1.000000 +vt 0.932998 0.498793 +vt 0.932998 1.000000 +vt 0.898909 0.498793 +vt 0.898909 1.000000 +vt 0.864819 0.498793 +vt 0.864819 1.000000 +vt 0.832040 0.498793 +vt 0.832040 1.000000 +vt 0.698509 0.326069 +vt 0.700251 0.317975 +vt 0.095308 0.026758 +vt 0.093951 0.032150 +vt 0.090017 0.030745 +vt 0.684652 0.371063 +vt 0.687480 0.363604 +vt 0.066055 0.053317 +vt 0.065470 0.058978 +vt 0.061417 0.058682 +vt 0.664835 0.411382 +vt 0.668641 0.404844 +vt 0.041038 0.087411 +vt 0.041248 0.093124 +vt 0.037232 0.093949 +vt 0.639819 0.445476 +vt 0.644456 0.440111 +vt 0.021221 0.127730 +vt 0.022218 0.133276 +vt 0.018393 0.135189 +vt 0.084560 1.000000 +vt 0.084560 0.498793 +vt 0.118156 1.000000 +vt 0.118156 0.498793 +vt 0.152410 1.000000 +vt 0.152410 0.498793 +vt 0.186006 1.000000 +vt 0.186006 0.498793 +vt 0.475164 0.487583 +vt 0.480906 0.490038 +vt 0.018393 0.363604 +vt 0.022217 0.365517 +vt 0.021221 0.371063 +vt 0.443248 0.468048 +vt 0.448539 0.472035 +vt 0.037232 0.404844 +vt 0.041248 0.405669 +vt 0.041038 0.411382 +vt 0.414647 0.440111 +vt 0.419285 0.445477 +vt 0.061417 0.440111 +vt 0.065470 0.439815 +vt 0.066054 0.445477 +vt 0.390463 0.404844 +vt 0.394269 0.411383 +vt 0.090017 0.468048 +vt 0.093951 0.466643 +vt 0.095308 0.472035 +vt 0.371623 0.363604 +vt 0.374451 0.371064 +vt 0.121934 0.487583 +vt 0.125598 0.485123 +vt 0.127675 0.490038 +vt 0.440000 0.498793 +vt 0.440000 1.000000 +vt 0.406404 0.498793 +vt 0.406404 1.000000 +vt 0.262625 0.468048 +vt 0.258691 0.466643 +vt 0.360595 0.172725 +vt 0.257334 0.472035 +vt 0.230708 0.487583 +vt 0.227044 0.485123 +vt 0.353231 0.220666 +vt 0.358853 0.180818 +vt 0.274372 0.995751 +vt 0.274372 0.503043 +vt 0.443247 0.030745 +vt 0.345278 0.326069 +vt 0.343533 0.320904 +vt 0.448539 0.026758 +vt 0.475164 0.011210 +vt 0.352642 0.278128 +vt 0.347020 0.317975 +vt 0.350216 0.273542 +vt 0.480905 0.008755 +vt 0.509171 0.000829 +vt 0.353231 0.229083 +vt 0.353231 0.269711 +vt 0.350216 0.225252 +vt 0.515142 0.000000 +vt 0.543961 0.000000 +vt 0.347020 0.180818 +vt 0.352642 0.220666 +vt 0.343534 0.177890 +vt 0.549932 0.000829 +vt 0.578198 0.008755 +vt 0.334250 0.135189 +vt 0.345279 0.172725 +vt 0.330425 0.133276 +vt 0.583939 0.011210 +vt 0.331422 0.127730 +vt 1.000000 0.503043 +vt 1.000000 0.995751 +vt 0.664835 0.087410 +vt 0.262626 0.030745 +vt 0.258692 0.032150 +vt 0.668641 0.093949 +vt 0.684652 0.127729 +vt 0.230709 0.011210 +vt 0.257335 0.026758 +vt 0.227045 0.013670 +vt 0.687480 0.135189 +vt 0.698509 0.172724 +vt 0.196702 0.000829 +vt 0.224968 0.008755 +vt 0.193449 0.004249 +vt 0.700251 0.180818 +vt 0.705873 0.220665 +vt 0.161912 0.000000 +vt 0.190731 0.000000 +vt 0.159194 0.004249 +vt 0.706461 0.229082 +vt 0.706461 0.269710 +vt 0.127675 0.008755 +vt 0.155941 0.000829 +vt 0.125598 0.013670 +vt 0.705873 0.278128 +vt 0.121934 0.011210 +vt 0.615856 0.468048 +vt 0.007364 0.172724 +vt 0.009109 0.177890 +vt 0.610565 0.472035 +vt 0.583939 0.487583 +vt 0.000000 0.220665 +vt 0.005622 0.180818 +vt 0.002426 0.225252 +vt 0.578198 0.490038 +vt 0.549932 0.497964 +vt 0.543962 0.498793 +vt 0.515142 0.498793 +vt 0.005622 0.317975 +vt 0.000000 0.278128 +vt 0.002426 0.273541 +vt 0.009109 0.320903 +vt 0.509171 0.497964 +vt 0.007364 0.326069 +vt 0.360595 0.326069 +vt 0.155941 0.497964 +vt 0.159194 0.494544 +vt 0.358853 0.317975 +vt 0.353231 0.278128 +vt 0.190731 0.498793 +vt 0.161912 0.498793 +vt 0.193448 0.494544 +vn 0.471400 0.000000 -0.881900 +vn -0.098000 0.000000 -0.995200 +vn 0.000000 -1.000000 0.000000 +vn 0.773000 0.000000 -0.634400 +vn 0.881900 0.000000 -0.471400 +vn 0.956900 0.000000 -0.290300 +vn 0.995200 0.000000 -0.098000 +vn 0.995200 0.000000 0.098000 +vn 0.956900 0.000000 0.290300 +vn 0.881900 0.000000 0.471400 +vn 0.773000 0.000000 0.634400 +vn 0.634400 0.000000 0.773000 +vn 0.471400 0.000000 0.881900 +vn 0.290300 0.000000 0.956900 +vn 0.098000 0.000000 0.995200 +vn -0.098000 0.000000 0.995200 +vn -0.290300 0.000000 0.956900 +vn -0.471400 0.000000 0.881900 +vn -0.634400 0.000000 0.773000 +vn -0.773000 0.000000 0.634400 +vn -0.881900 0.000000 0.471400 +vn -0.956900 -0.000000 0.290300 +vn -0.995200 0.000000 0.098000 +vn -0.995200 0.000000 -0.098000 +vn -0.956900 0.000000 -0.290300 +vn -0.881900 0.000000 -0.471400 +vn -0.773000 0.000000 -0.634400 +vn -0.634400 0.000000 -0.773000 +vn -0.471400 0.000000 -0.881900 +vn -0.290300 0.000000 -0.956900 +vn 0.634400 0.000000 -0.773000 +vn 0.098000 0.000000 -0.995200 +vn 0.290300 0.000000 -0.956900 +vn 0.283500 0.671800 -0.684400 +vn 0.283500 -0.671800 -0.684400 +vn 0.144500 0.671800 -0.726500 +vn 0.144500 -0.671800 -0.726500 +vn 0.000000 0.671800 -0.740800 +vn 0.000000 -0.671800 -0.740800 +vn 0.411500 -0.671800 -0.615900 +vn 0.411500 0.671700 -0.615900 +vn 0.523800 -0.671800 -0.523800 +vn 0.523800 0.671800 -0.523800 +vn 0.615900 -0.671700 -0.411600 +vn 0.615900 0.671700 -0.411600 +vn 0.684400 -0.671800 -0.283500 +vn 0.684400 0.671800 -0.283500 +vn 0.726500 -0.671800 -0.144500 +vn 0.726500 0.671800 -0.144500 +vn 0.740800 -0.671800 0.000000 +vn 0.740800 0.671800 0.000000 +vn 0.726500 -0.671800 0.144500 +vn 0.726500 0.671800 0.144500 +vn 0.684400 -0.671800 0.283500 +vn 0.684400 0.671800 0.283500 +vn 0.615900 -0.671700 0.411600 +vn 0.615900 0.671700 0.411600 +vn 0.523800 -0.671700 0.523800 +vn 0.523800 0.671800 0.523800 +vn 0.411600 -0.671700 0.615900 +vn 0.411600 0.671700 0.615900 +vn 0.283500 -0.671700 0.684400 +vn 0.283500 0.671800 0.684400 +vn 0.144500 -0.671800 0.726500 +vn 0.144500 0.671800 0.726500 +vn 0.000000 -0.671700 0.740800 +vn 0.000000 0.671800 0.740800 +vn -0.144500 -0.671800 0.726500 +vn -0.144500 0.671800 0.726500 +vn -0.283500 -0.671800 0.684400 +vn -0.283500 0.671700 0.684400 +vn -0.411600 -0.671700 0.615900 +vn -0.411600 0.671700 0.615900 +vn -0.523800 -0.671800 0.523800 +vn -0.523800 0.671700 0.523800 +vn -0.615900 -0.671700 0.411600 +vn -0.615900 0.671700 0.411600 +vn -0.684400 -0.671800 0.283500 +vn -0.684400 0.671800 0.283500 +vn -0.726500 -0.671800 0.144500 +vn -0.726500 0.671800 0.144500 +vn -0.740800 -0.671800 0.000000 +vn -0.740800 0.671800 0.000000 +vn -0.726500 -0.671800 -0.144500 +vn -0.726500 0.671800 -0.144500 +vn -0.684400 -0.671800 -0.283500 +vn -0.684400 0.671800 -0.283500 +vn -0.615900 -0.671700 -0.411600 +vn -0.615900 0.671700 -0.411600 +vn -0.523800 -0.671800 -0.523800 +vn -0.523800 0.671800 -0.523800 +vn -0.411600 -0.671700 -0.615900 +vn -0.411600 0.671700 -0.615900 +vn -0.283500 -0.671800 -0.684400 +vn -0.283500 0.671800 -0.684400 +vn -0.144500 -0.671800 -0.726500 +vn -0.144500 0.671800 -0.726500 +vn 0.205300 0.707100 -0.676700 +vn 0.205300 -0.707100 -0.676700 +vn 0.195100 0.000000 -0.980800 +vn 0.000000 0.000000 -1.000000 +vn 0.069300 0.707100 -0.703700 +vn 0.069300 -0.707100 -0.703700 +vn 0.382700 0.000000 -0.923900 +vn 0.333300 -0.707100 -0.623600 +vn 0.333300 0.707100 -0.623600 +vn 0.555600 0.000000 -0.831500 +vn 0.448600 -0.707100 -0.546600 +vn 0.448600 0.707100 -0.546600 +vn 0.707100 0.000000 -0.707100 +vn 0.546600 -0.707100 -0.448600 +vn 0.546600 0.707100 -0.448600 +vn 0.831500 0.000000 -0.555600 +vn 0.623600 -0.707100 -0.333300 +vn 0.623600 0.707100 -0.333300 +vn 0.923900 0.000000 -0.382700 +vn 0.676700 -0.707100 -0.205300 +vn 0.676700 0.707100 -0.205300 +vn 0.980800 0.000000 -0.195100 +vn 0.703700 -0.707100 -0.069300 +vn 0.703700 0.707100 -0.069300 +vn 1.000000 -0.000000 0.000000 +vn 0.703700 -0.707100 0.069300 +vn 0.703700 0.707100 0.069300 +vn 0.980800 0.000000 0.195100 +vn 0.676700 -0.707100 0.205300 +vn 0.676700 0.707100 0.205300 +vn 0.923900 0.000000 0.382700 +vn 0.623600 -0.707100 0.333300 +vn 0.623600 0.707100 0.333300 +vn 0.831500 0.000000 0.555600 +vn 0.546600 -0.707100 0.448600 +vn 0.546600 0.707100 0.448600 +vn 0.707100 0.000000 0.707100 +vn 0.448600 -0.707100 0.546600 +vn 0.448600 0.707100 0.546600 +vn 0.555600 0.000000 0.831500 +vn 0.333300 -0.707100 0.623600 +vn 0.333300 0.707100 0.623600 +vn 0.382700 0.000000 0.923900 +vn 0.205300 -0.707100 0.676700 +vn 0.205300 0.707100 0.676700 +vn 0.195100 0.000000 0.980800 +vn 0.069300 -0.707100 0.703700 +vn 0.069300 0.707100 0.703700 +vn 0.000000 0.000000 1.000000 +vn -0.069300 -0.707100 0.703700 +vn -0.069300 0.707100 0.703700 +vn -0.195100 0.000000 0.980800 +vn -0.205300 -0.707100 0.676700 +vn -0.205300 0.707100 0.676700 +vn -0.382700 0.000000 0.923900 +vn -0.333300 -0.707100 0.623600 +vn -0.333300 0.707100 0.623600 +vn -0.555600 0.000000 0.831500 +vn -0.448600 -0.707100 0.546600 +vn -0.448600 0.707100 0.546600 +vn -0.707100 0.000000 0.707100 +vn -0.546600 -0.707100 0.448600 +vn -0.546600 0.707100 0.448600 +vn -0.831500 0.000000 0.555600 +vn -0.623600 -0.707100 0.333300 +vn -0.623600 0.707100 0.333300 +vn -0.923900 0.000000 0.382700 +vn -0.676700 -0.707100 0.205300 +vn -0.676700 0.707100 0.205300 +vn -0.980800 0.000000 0.195100 +vn -0.703700 -0.707100 0.069300 +vn -0.703700 0.707100 0.069300 +vn -1.000000 0.000000 0.000000 +vn -0.703700 -0.707100 -0.069300 +vn -0.703700 0.707100 -0.069300 +vn -0.980800 0.000000 -0.195100 +vn -0.676700 -0.707100 -0.205300 +vn -0.676700 0.707100 -0.205300 +vn -0.923900 0.000000 -0.382700 +vn -0.623600 -0.707100 -0.333300 +vn -0.623600 0.707100 -0.333300 +vn -0.831500 0.000000 -0.555600 +vn -0.546600 -0.707100 -0.448600 +vn -0.546600 0.707100 -0.448600 +vn -0.707100 0.000000 -0.707100 +vn -0.448600 -0.707100 -0.546600 +vn -0.448600 0.707100 -0.546600 +vn -0.555600 0.000000 -0.831500 +vn -0.333300 -0.707100 -0.623600 +vn -0.333300 0.707100 -0.623600 +vn -0.382700 0.000000 -0.923900 +vn -0.205300 -0.707100 -0.676700 +vn -0.205300 0.707100 -0.676700 +vn -0.195100 0.000000 -0.980800 +vn -0.069300 -0.707100 -0.703700 +vn -0.069300 0.707100 -0.703700 +vn 0.000000 1.000000 -0.000000 +s off +f 4/1/1 3/2/1 22/3/1 21/4/1 +f 187/5/2 192/6/2 14/7/2 17/8/2 +f 16/9/3 11/10/3 5/11/3 20/12/3 26/13/3 32/14/3 38/15/3 44/16/3 50/17/3 56/18/3 62/19/3 68/20/3 74/21/3 80/22/3 86/23/3 92/24/3 98/25/3 104/26/3 110/27/3 116/28/3 122/29/3 128/30/3 134/31/3 140/32/3 146/33/3 152/34/3 158/35/3 164/36/3 170/37/3 176/38/3 182/39/3 188/40/3 +f 25/41/4 30/42/4 34/43/4 33/44/4 +f 31/45/5 36/46/5 40/47/5 39/48/5 +f 37/49/6 42/50/6 46/51/6 45/52/6 +f 43/53/7 48/54/7 52/55/7 51/56/7 +f 49/57/8 54/58/8 58/59/8 57/60/8 +f 55/61/9 60/62/9 64/63/9 63/64/9 +f 61/65/10 66/66/10 70/67/10 69/68/10 +f 67/69/11 72/70/11 76/71/11 75/72/11 +f 73/73/12 78/74/12 82/75/12 81/76/12 +f 79/77/13 84/78/13 88/79/13 87/80/13 +f 85/81/14 90/82/14 94/83/14 93/84/14 +f 91/85/15 96/86/15 100/87/15 99/88/15 +f 97/89/16 102/90/16 106/91/16 105/92/16 +f 103/93/17 108/94/17 112/95/17 111/96/17 +f 109/97/18 114/98/18 118/99/18 117/100/18 +f 115/101/19 120/102/19 124/103/19 123/104/19 +f 121/105/20 126/106/20 130/107/20 129/108/20 +f 127/109/21 132/110/21 136/111/21 135/112/21 +f 133/113/22 138/114/22 142/115/22 141/116/22 +f 139/117/23 144/118/23 148/119/23 147/120/23 +f 145/121/24 150/122/24 154/123/24 153/124/24 +f 151/125/25 156/126/25 160/127/25 159/128/25 +f 157/129/26 162/130/26 166/131/26 165/132/26 +f 163/68/27 168/67/27 172/133/27 171/134/27 +f 169/135/28 174/136/28 178/137/28 177/138/28 +f 175/139/29 180/140/29 184/141/29 183/142/29 +f 181/143/30 186/144/30 190/145/30 189/146/30 +f 19/147/31 24/148/31 28/149/31 27/150/31 +f 18/151/32 13/152/32 7/153/32 12/154/32 +f 10/155/33 9/156/33 1/157/33 6/158/33 +f 1/159/34 2/160/34 3/161/34 +f 4/162/35 5/11/35 6/163/35 +f 7/153/36 8/164/36 9/156/36 +f 10/155/37 11/165/37 12/154/37 +f 13/152/38 14/7/38 15/166/38 +f 16/167/39 17/8/39 18/151/39 +f 19/168/40 20/12/40 21/169/40 +f 22/170/41 23/171/41 24/172/41 +f 25/173/42 26/13/42 27/174/42 +f 28/175/43 29/176/43 30/177/43 +f 31/45/44 32/178/44 33/44/44 +f 34/43/45 35/179/45 36/46/45 +f 37/49/46 38/180/46 39/48/46 +f 40/47/47 41/181/47 42/50/47 +f 43/53/48 44/182/48 45/52/48 +f 46/51/49 47/183/49 48/54/49 +f 49/57/50 50/184/50 51/56/50 +f 52/55/51 53/185/51 54/58/51 +f 55/61/52 56/186/52 57/60/52 +f 58/59/53 59/187/53 60/62/53 +f 61/188/54 62/19/54 63/189/54 +f 64/190/55 65/191/55 66/192/55 +f 67/193/56 68/20/56 69/194/56 +f 70/195/57 71/196/57 72/197/57 +f 73/73/58 74/198/58 75/72/58 +f 76/71/59 77/199/59 78/74/59 +f 79/77/60 80/200/60 81/76/60 +f 82/75/61 83/201/61 84/78/61 +f 85/81/62 86/202/62 87/80/62 +f 88/79/63 89/203/63 90/82/63 +f 91/85/64 92/204/64 93/84/64 +f 94/83/65 95/205/65 96/86/65 +f 97/89/66 98/206/66 99/88/66 +f 100/87/67 101/207/67 102/90/67 +f 103/208/68 104/26/68 105/209/68 +f 106/210/69 107/211/69 108/212/69 +f 109/213/70 110/27/70 111/214/70 +f 112/215/71 113/216/71 114/217/71 +f 115/218/72 116/28/72 117/219/72 +f 118/220/73 119/221/73 120/222/73 +f 121/223/74 122/29/74 123/224/74 +f 124/225/75 125/226/75 126/227/75 +f 127/109/76 128/228/76 129/108/76 +f 130/107/77 131/229/77 132/110/77 +f 133/113/78 134/230/78 135/112/78 +f 136/111/79 137/231/79 138/114/79 +f 139/117/80 140/232/80 141/116/80 +f 142/115/81 143/233/81 144/118/81 +f 145/121/82 146/234/82 147/120/82 +f 148/119/83 149/235/83 150/122/83 +f 151/236/84 152/34/84 153/237/84 +f 154/238/85 155/239/85 156/240/85 +f 157/241/86 158/35/86 159/242/86 +f 160/243/87 161/244/87 162/245/87 +f 163/246/88 164/36/88 165/247/88 +f 166/248/89 167/249/89 168/250/89 +f 169/251/90 170/37/90 171/252/90 +f 172/253/91 173/254/91 174/255/91 +f 175/256/92 176/38/92 177/257/92 +f 178/258/93 179/259/93 180/260/93 +f 181/143/94 182/261/94 183/142/94 +f 184/141/95 185/262/95 186/144/95 +f 187/5/96 188/263/96 189/146/96 +f 190/145/97 191/264/97 192/6/97 +f 1/159/98 9/265/98 8/266/98 2/160/98 +f 10/267/99 6/163/99 5/11/99 11/10/99 +f 9/156/100 10/155/100 12/154/100 7/153/100 +f 17/8/101 14/7/101 13/152/101 18/151/101 +f 7/268/102 13/269/102 15/270/102 8/266/102 +f 18/271/103 12/272/103 11/10/103 16/9/103 +f 3/2/104 4/1/104 6/158/104 1/157/104 +f 4/162/105 21/169/105 20/12/105 5/11/105 +f 22/170/106 3/161/106 2/160/106 23/171/106 +f 24/273/107 19/274/107 21/4/107 22/3/107 +f 19/168/108 27/174/108 26/13/108 20/12/108 +f 28/175/109 24/172/109 23/171/109 29/176/109 +f 30/42/110 25/41/110 27/150/110 28/149/110 +f 25/173/111 33/275/111 32/14/111 26/13/111 +f 34/276/112 30/177/112 29/176/112 35/277/112 +f 36/46/113 31/45/113 33/44/113 34/43/113 +f 31/278/114 39/279/114 38/15/114 32/14/114 +f 40/280/115 36/281/115 35/277/115 41/282/115 +f 42/50/116 37/49/116 39/48/116 40/47/116 +f 37/283/117 45/284/117 44/16/117 38/15/117 +f 46/285/118 42/286/118 41/282/118 47/287/118 +f 48/54/119 43/53/119 45/52/119 46/51/119 +f 43/288/120 51/289/120 50/17/120 44/16/120 +f 52/290/121 48/291/121 47/287/121 53/292/121 +f 54/58/122 49/57/122 51/56/122 52/55/122 +f 49/293/123 57/294/123 56/18/123 50/17/123 +f 58/295/124 54/296/124 53/292/124 59/297/124 +f 60/62/125 55/61/125 57/60/125 58/59/125 +f 55/298/126 63/189/126 62/19/126 56/18/126 +f 64/190/127 60/299/127 59/297/127 65/191/127 +f 66/66/128 61/65/128 63/64/128 64/63/128 +f 61/188/129 69/194/129 68/20/129 62/19/129 +f 70/195/130 66/192/130 65/191/130 71/196/130 +f 72/70/131 67/69/131 69/300/131 70/301/131 +f 67/193/132 75/302/132 74/21/132 68/20/132 +f 76/303/133 72/197/133 71/196/133 77/304/133 +f 78/74/134 73/73/134 75/72/134 76/71/134 +f 73/305/135 81/306/135 80/22/135 74/21/135 +f 82/307/136 78/308/136 77/304/136 83/309/136 +f 84/78/137 79/77/137 81/76/137 82/75/137 +f 79/310/138 87/311/138 86/23/138 80/22/138 +f 88/312/139 84/313/139 83/309/139 89/314/139 +f 90/82/140 85/81/140 87/80/140 88/79/140 +f 85/315/141 93/316/141 92/24/141 86/23/141 +f 94/317/142 90/318/142 89/314/142 95/319/142 +f 96/86/143 91/85/143 93/84/143 94/83/143 +f 91/320/144 99/321/144 98/25/144 92/24/144 +f 100/322/145 96/323/145 95/319/145 101/324/145 +f 102/90/146 97/89/146 99/88/146 100/87/146 +f 97/325/147 105/209/147 104/26/147 98/25/147 +f 106/210/148 102/326/148 101/324/148 107/211/148 +f 108/94/149 103/93/149 105/92/149 106/91/149 +f 103/208/150 111/214/150 110/27/150 104/26/150 +f 112/215/151 108/212/151 107/211/151 113/216/151 +f 114/148/152 109/147/152 111/96/152 112/95/152 +f 109/213/153 117/219/153 116/28/153 110/27/153 +f 118/220/154 114/217/154 113/216/154 119/221/154 +f 120/102/155 115/101/155 117/100/155 118/99/155 +f 115/218/156 123/224/156 122/29/156 116/28/156 +f 124/225/157 120/222/157 119/221/157 125/226/157 +f 126/106/158 121/105/158 123/104/158 124/103/158 +f 121/223/159 129/327/159 128/30/159 122/29/159 +f 130/328/160 126/227/160 125/226/160 131/329/160 +f 132/110/161 127/109/161 129/108/161 130/107/161 +f 127/330/162 135/331/162 134/31/162 128/30/162 +f 136/332/163 132/333/163 131/329/163 137/334/163 +f 138/114/164 133/113/164 135/112/164 136/111/164 +f 133/335/165 141/336/165 140/32/165 134/31/165 +f 142/115/166 138/114/166 137/231/166 143/233/166 +f 144/118/167 139/117/167 141/116/167 142/115/167 +f 139/337/168 147/338/168 146/33/168 140/32/168 +f 148/339/169 144/340/169 143/341/169 149/342/169 +f 150/122/170 145/121/170 147/120/170 148/119/170 +f 145/343/171 153/237/171 152/34/171 146/33/171 +f 154/238/172 150/344/172 149/342/172 155/239/172 +f 156/126/173 151/125/173 153/124/173 154/123/173 +f 151/236/174 159/242/174 158/35/174 152/34/174 +f 160/243/175 156/240/175 155/239/175 161/244/175 +f 162/130/176 157/129/176 159/128/176 160/127/176 +f 157/241/177 165/247/177 164/36/177 158/35/177 +f 166/248/178 162/245/178 161/244/178 167/249/178 +f 168/274/179 163/273/179 165/132/179 166/131/179 +f 163/246/180 171/252/180 170/37/180 164/36/180 +f 172/253/181 168/250/181 167/249/181 173/254/181 +f 174/136/182 169/135/182 171/134/182 172/133/182 +f 169/251/183 177/257/183 176/38/183 170/37/183 +f 178/258/184 174/255/184 173/254/184 179/259/184 +f 180/140/185 175/139/185 177/138/185 178/137/185 +f 175/256/186 183/345/186 182/39/186 176/38/186 +f 184/346/187 180/260/187 179/259/187 185/347/187 +f 186/144/188 181/143/188 183/142/188 184/141/188 +f 181/348/189 189/349/189 188/40/189 182/39/189 +f 190/350/190 186/351/190 185/347/190 191/352/190 +f 192/6/191 187/5/191 189/146/191 190/145/191 +f 187/5/192 17/8/192 16/167/192 188/263/192 +f 14/7/193 192/6/193 191/264/193 15/166/193 +f 2/160/194 8/266/194 15/270/194 191/352/194 185/347/194 179/259/194 173/254/194 167/249/194 161/244/194 155/239/194 149/342/194 143/341/194 137/334/194 131/329/194 125/226/194 119/221/194 113/216/194 107/211/194 101/324/194 95/319/194 89/314/194 83/309/194 77/304/194 71/196/194 65/191/194 59/297/194 53/292/194 47/287/194 41/282/194 35/277/194 29/176/194 23/171/194 diff --git a/Levels/Geometry/Marble.obj b/Levels/Geometry/Marble.obj new file mode 100644 index 0000000..73fd3a9 --- /dev/null +++ b/Levels/Geometry/Marble.obj @@ -0,0 +1,2161 @@ +# Blender v2.71 (sub 0) OBJ File: 'marble1.blend' +# www.blender.org +o Marble_Cube +v -0.101512 -0.191160 -0.975255 +v -0.213683 -0.341397 -0.918021 +v -0.316912 -0.479880 -0.825308 +v -0.407232 -0.601287 -0.700680 +v -0.481172 -0.700952 -0.548927 +v -0.535891 -0.775046 -0.375879 +v -0.567836 -0.820949 0.201990 +v -0.533049 -0.775495 0.389482 +v -0.477046 -0.701605 0.562206 +v -0.401981 -0.602118 0.713523 +v -0.310737 -0.480857 0.837619 +v -0.206822 -0.342482 0.929725 +v -0.094228 -0.192311 0.986301 +v -0.068792 -0.210959 -0.975388 +v -0.149501 -0.380235 -0.918282 +v -0.223734 -0.536265 -0.825687 +v -0.288638 -0.673051 -0.701163 +v -0.341721 -0.785338 -0.549494 +v -0.380940 -0.868809 -0.376509 +v -0.403342 -0.920488 0.201321 +v -0.378098 -0.869259 0.388852 +v -0.337595 -0.785990 0.561638 +v -0.283387 -0.673881 0.713041 +v -0.217559 -0.537241 0.837240 +v -0.142639 -0.381320 0.929464 +v -0.061508 -0.212111 0.986168 +v -0.032838 -0.223995 -0.975530 +v -0.078975 -0.405806 -0.918559 +v -0.121346 -0.573387 -0.826089 +v -0.158323 -0.720299 -0.701675 +v -0.188486 -0.840895 -0.550096 +v -0.210675 -0.930542 -0.377178 +v -0.224038 -0.985794 -0.189566 +v -0.222589 -0.986023 0.200611 +v -0.207833 -0.930991 0.388183 +v -0.184360 -0.841548 0.561037 +v -0.153072 -0.721129 0.712529 +v -0.115171 -0.574363 0.836838 +v -0.072113 -0.406890 0.929187 +v -0.025554 -0.225146 0.986027 +v 0.004968 -0.229766 -0.975673 +v -0.004815 -0.417126 -0.918841 +v -0.013683 -0.589821 -0.826499 +v -0.021294 -0.741216 -0.702196 +v -0.027357 -0.865491 -0.550709 +v -0.031638 -0.957871 -0.377859 +v -0.032524 -1.015035 0.199888 +v -0.028796 -0.958320 0.387502 +v -0.023231 -0.866143 0.560424 +v -0.016043 -0.742046 0.712008 +v -0.007508 -0.590798 0.836429 +v 0.002046 -0.418211 0.928905 +v 0.012252 -0.230917 0.985883 +v 0.043174 -0.228050 -0.975814 +v 0.070128 -0.413760 -0.919117 +v 0.095118 -0.584936 -0.826900 +v 0.117183 -0.734997 -0.702706 +v 0.135475 -0.858179 -0.551309 +v 0.149290 -0.949746 -0.378526 +v 0.159548 -1.006410 0.199180 +v 0.152132 -0.950196 0.386835 +v 0.139601 -0.858831 0.559824 +v 0.122434 -0.735828 0.711497 +v 0.101293 -0.585912 0.836028 +v 0.076989 -0.414845 0.928629 +v 0.050458 -0.229202 0.985743 +v 0.080310 -0.218914 -0.975947 +v 0.142975 -0.395839 -0.919377 +v 0.200875 -0.558917 -0.827277 +v 0.251786 -0.701882 -0.703187 +v 0.293751 -0.819240 -0.551874 +v 0.325157 -0.906480 -0.379154 +v 0.344799 -0.960250 -0.191664 +v 0.346248 -0.960479 0.198514 +v 0.327999 -0.906929 0.386208 +v 0.297877 -0.819892 0.559259 +v 0.257037 -0.702713 0.711017 +v 0.207050 -0.559894 0.835650 +v 0.149836 -0.396924 0.928369 +v 0.087594 -0.220065 0.985610 +v 0.114951 -0.202708 -0.976066 +v 0.210925 -0.364050 -0.919611 +v 0.299524 -0.512767 -0.827617 +v 0.377342 -0.643144 -0.703618 +v 0.441389 -0.750171 -0.552382 +v 0.489205 -0.829735 -0.379718 +v 0.518950 -0.878777 -0.192263 +v 0.520399 -0.879006 0.197915 +v 0.492047 -0.830184 0.385644 +v 0.445515 -0.750824 0.558751 +v 0.382593 -0.643975 0.710585 +v 0.305699 -0.513744 0.835311 +v 0.217787 -0.365135 0.928135 +v 0.122235 -0.203859 0.985491 +v 0.145765 -0.180055 -0.976167 +v 0.271369 -0.319615 -0.919809 +v 0.387274 -0.448258 -0.827905 +v 0.489026 -0.561040 -0.703985 +v 0.572716 -0.653627 -0.552813 +v 0.635127 -0.722460 -0.380197 +v 0.675310 -0.765124 0.197407 +v 0.637970 -0.722910 0.385165 +v 0.576842 -0.654279 0.558320 +v 0.494278 -0.561870 0.710219 +v 0.393449 -0.449235 0.835023 +v 0.278230 -0.320700 0.927937 +v 0.153049 -0.181207 0.985390 +v 0.171568 -0.151826 -0.976246 +v 0.321982 -0.264243 -0.919965 +v 0.460753 -0.367869 -0.828130 +v 0.582547 -0.458724 -0.704272 +v 0.682685 -0.533316 -0.553150 +v 0.757319 -0.588778 -0.380572 +v 0.805028 -0.623208 0.197008 +v 0.760161 -0.589228 0.384789 +v 0.686812 -0.533969 0.557982 +v 0.587799 -0.459555 0.709931 +v 0.466928 -0.368846 0.834797 +v 0.328843 -0.265327 0.927782 +v 0.178851 -0.152978 0.985310 +v 0.191367 -0.119106 -0.976301 +v 0.360820 -0.200060 -0.920071 +v 0.517137 -0.274690 -0.828285 +v 0.654311 -0.340130 -0.704469 +v 0.767070 -0.393864 -0.553382 +v 0.851082 -0.433827 -0.380829 +v 0.904566 -0.458713 0.196735 +v 0.853924 -0.434276 0.384532 +v 0.771196 -0.394516 0.557751 +v 0.659562 -0.340960 0.709735 +v 0.523312 -0.275666 0.834643 +v 0.367681 -0.201144 0.927675 +v 0.198651 -0.120258 0.985256 +v 0.204403 -0.083152 -0.976328 +v 0.386390 -0.129533 -0.920125 +v 0.554259 -0.172301 -0.828363 +v 0.701559 -0.209813 -0.704568 +v 0.822628 -0.240628 -0.553498 +v 0.912815 -0.263561 -0.380958 +v 0.968652 -0.277730 -0.193580 +v 0.970101 -0.277959 0.196598 +v 0.915657 -0.264010 0.384403 +v 0.826754 -0.241280 0.557635 +v 0.706810 -0.210644 0.709636 +v 0.560434 -0.173278 0.834565 +v 0.393252 -0.130618 0.927621 +v 0.211687 -0.084304 0.985229 +v 0.210174 -0.045345 -0.976327 +v 0.397711 -0.055373 -0.920123 +v 0.570694 -0.064637 -0.828361 +v 0.722476 -0.072783 -0.704565 +v 0.847224 -0.079498 -0.553495 +v 0.940144 -0.084522 -0.380955 +v 0.997665 -0.087664 -0.193576 +v 0.999114 -0.087893 0.196602 +v 0.942986 -0.084972 0.384407 +v 0.851350 -0.080150 0.557638 +v 0.727727 -0.073614 0.709638 +v 0.576869 -0.065614 0.834567 +v 0.404572 -0.056458 0.927623 +v 0.217457 -0.046497 0.985230 +v 0.208458 -0.007139 -0.976298 +v 0.394345 0.019571 -0.920067 +v 0.565808 0.044164 -0.828278 +v 0.716258 0.065694 -0.704461 +v 0.839912 0.083335 -0.553372 +v 0.932019 0.096407 -0.380818 +v 0.989040 0.104410 -0.193431 +v 0.990489 0.104181 0.196747 +v 0.934862 0.095958 0.384543 +v 0.844038 0.082682 0.557761 +v 0.721509 0.064864 0.709743 +v 0.571983 0.043187 0.834649 +v 0.401206 0.018486 0.927679 +v 0.215742 -0.008291 0.985258 +v 0.199322 0.029998 -0.976243 +v 0.376424 0.092418 -0.919957 +v 0.539791 0.149921 -0.828120 +v 0.683144 0.200298 -0.704259 +v 0.800974 0.241612 -0.553134 +v 0.888754 0.272275 -0.380554 +v 0.944558 0.290881 0.197027 +v 0.891596 0.271826 0.384807 +v 0.805100 0.240959 0.557998 +v 0.688395 0.199467 0.709945 +v 0.545965 0.148945 0.834808 +v 0.383285 0.091333 0.927789 +v 0.206606 0.028846 0.985314 +v 0.183116 0.064639 -0.976162 +v 0.344636 0.160369 -0.919800 +v 0.493641 0.248571 -0.827891 +v 0.624406 0.325855 -0.703967 +v 0.731906 0.389251 -0.552791 +v 0.812010 0.436324 -0.380173 +v 0.863087 0.465034 0.197432 +v 0.814852 0.435874 0.385188 +v 0.736032 0.388599 0.558341 +v 0.629658 0.325024 0.710237 +v 0.499816 0.247594 0.835037 +v 0.351497 0.159284 0.927947 +v 0.190400 0.063487 0.985395 +v 0.160464 0.095453 -0.976060 +v 0.300201 0.220812 -0.919599 +v 0.429132 0.336321 -0.827599 +v 0.542302 0.437540 -0.703596 +v 0.635362 0.520579 -0.552356 +v 0.704736 0.582247 -0.379689 +v 0.749206 0.619946 0.197946 +v 0.707578 0.581798 0.385672 +v 0.639488 0.519926 0.558777 +v 0.547554 0.436710 0.710607 +v 0.435307 0.335345 0.835328 +v 0.307063 0.219727 0.928147 +v 0.167748 0.094301 0.985497 +v 0.132235 0.121255 -0.975940 +v 0.244829 0.271426 -0.919364 +v 0.348744 0.409800 -0.827258 +v 0.439988 0.531061 -0.703162 +v 0.515053 0.630548 -0.551844 +v 0.571056 0.704439 -0.379121 +v 0.605843 0.749892 -0.191629 +v 0.607292 0.749663 0.198549 +v 0.573898 0.703989 0.386240 +v 0.519179 0.629896 0.559288 +v 0.445239 0.530231 0.711042 +v 0.354919 0.408824 0.835670 +v 0.251690 0.270341 0.928382 +v 0.139519 0.120103 0.985617 +v 0.099515 0.141055 -0.975807 +v 0.180647 0.310264 -0.919102 +v 0.255566 0.466185 -0.826879 +v 0.321394 0.602825 -0.702679 +v 0.375601 0.714934 -0.551277 +v 0.416105 0.798203 -0.378490 +v 0.442797 0.849202 0.199218 +v 0.418948 0.797753 0.386871 +v 0.379727 0.714281 0.559856 +v 0.326645 0.601994 0.711524 +v 0.261741 0.465208 0.836049 +v 0.187508 0.309179 0.928644 +v 0.106799 0.139903 0.985750 +v 0.063562 0.154090 -0.975666 +v 0.110120 0.335834 -0.918826 +v 0.153178 0.503307 -0.826477 +v 0.191079 0.650073 -0.702167 +v 0.222367 0.770491 -0.550675 +v 0.245840 0.859935 -0.377822 +v 0.262045 0.914737 0.199928 +v 0.248682 0.859486 0.387539 +v 0.226493 0.769839 0.560457 +v 0.196330 0.649243 0.712036 +v 0.159353 0.502331 0.836451 +v 0.116982 0.334749 0.928921 +v 0.070845 0.152938 0.985891 +v 0.025755 0.159861 -0.975522 +v 0.035961 0.347154 -0.918544 +v 0.045515 0.519741 -0.826067 +v 0.054050 0.670990 -0.701646 +v 0.061238 0.795087 -0.550062 +v 0.066803 0.887264 -0.377141 +v 0.070531 0.943979 -0.189527 +v 0.071980 0.943750 0.200651 +v 0.069645 0.886815 0.388220 +v 0.065364 0.794434 0.561070 +v 0.059301 0.670159 0.712557 +v 0.051690 0.518765 0.836860 +v 0.042822 0.346069 0.929203 +v 0.033039 0.158709 0.986035 +v -0.012450 0.158146 -0.975381 +v -0.038982 0.343789 -0.918267 +v -0.063286 0.514856 -0.825666 +v -0.084427 0.664771 -0.701136 +v -0.101593 0.787774 -0.549462 +v -0.114125 0.879139 -0.376474 +v -0.121541 0.935353 -0.188819 +v -0.120092 0.935124 0.201359 +v -0.111283 0.878690 0.388887 +v -0.097467 0.787122 0.561670 +v -0.079176 0.663941 0.713068 +v -0.057111 0.513879 0.837262 +v -0.032121 0.342704 0.929479 +v -0.005166 0.156994 0.986176 +v -0.049587 0.149009 -0.975248 +v -0.111829 0.325868 -0.918007 +v -0.169042 0.488838 -0.825289 +v -0.219030 0.631657 -0.700655 +v -0.259870 0.748836 -0.548897 +v -0.289992 0.835873 -0.375846 +v -0.308241 0.889422 -0.188153 +v -0.306792 0.889193 0.202025 +v -0.287150 0.835424 0.389515 +v -0.255744 0.748183 0.562235 +v -0.213778 0.630826 0.713548 +v -0.162868 0.487861 0.837639 +v -0.104967 0.324783 0.929739 +v -0.042303 0.147857 0.986308 +v 0.022717 -0.036115 1.005174 +v -0.084228 0.132804 -0.975129 +v -0.179779 0.294079 -0.917774 +v -0.267691 0.442687 -0.824949 +v -0.344586 0.572919 -0.700224 +v -0.407508 0.679767 -0.548390 +v -0.454039 0.759128 -0.375282 +v -0.480943 0.807721 0.202624 +v -0.451197 0.758679 0.390079 +v -0.403382 0.679115 0.562743 +v -0.339335 0.572088 0.713980 +v -0.261516 0.441711 0.837978 +v -0.172918 0.292994 0.929973 +v -0.076944 0.131652 0.986427 +v -0.115042 0.110151 -0.975028 +v -0.240222 0.249644 -0.917575 +v -0.355441 0.378178 -0.824661 +v -0.456271 0.490814 -0.699857 +v -0.538835 0.583223 -0.547959 +v -0.599962 0.651853 -0.374803 +v -0.635854 0.693839 0.203132 +v -0.597120 0.651404 0.390558 +v -0.534709 0.582570 0.563174 +v -0.451019 0.489984 0.714346 +v -0.349266 0.377202 0.838266 +v -0.233361 0.248559 0.930171 +v -0.107758 0.108999 0.986529 +v -0.140844 0.081922 -0.974949 +v -0.290836 0.194271 -0.917420 +v -0.428920 0.297790 -0.824436 +v -0.549792 0.388499 -0.699570 +v -0.648804 0.462912 -0.547621 +v -0.722153 0.518172 -0.374428 +v -0.765571 0.551923 0.203531 +v -0.719311 0.517722 0.390933 +v -0.644678 0.462260 0.563512 +v -0.544540 0.387668 0.714634 +v -0.422745 0.296813 0.838492 +v -0.283974 0.193186 0.930326 +v -0.133560 0.080770 0.986608 +v -0.160644 0.049202 -0.974895 +v -0.329674 0.130088 -0.917313 +v -0.485305 0.204610 -0.824281 +v -0.621555 0.269904 -0.699373 +v -0.733189 0.323460 -0.547389 +v -0.815917 0.363220 -0.374171 +v -0.865110 0.387428 0.203804 +v -0.813075 0.362771 0.391190 +v -0.729063 0.322807 0.563743 +v -0.616304 0.269073 0.714831 +v -0.479129 0.203634 0.838647 +v -0.322812 0.129003 0.930433 +v -0.153360 0.048050 0.986662 +v -0.173680 0.013248 -0.974867 +v -0.355244 0.059562 -0.917260 +v -0.522427 0.102221 -0.824203 +v -0.668803 0.139588 -0.699274 +v -0.788746 0.170224 -0.547273 +v -0.877649 0.192954 -0.374042 +v -0.930645 0.206674 0.203941 +v -0.874807 0.192504 0.391320 +v -0.784620 0.169572 0.563860 +v -0.663552 0.138757 0.714929 +v -0.516252 0.101245 0.838724 +v -0.348383 0.058477 0.930486 +v -0.166395 0.012096 0.986689 +v -0.179450 -0.024559 -0.974868 +v -0.366564 -0.014598 -0.917261 +v -0.538861 -0.005442 -0.824206 +v -0.689720 0.002558 -0.699277 +v -0.813342 0.009094 -0.547276 +v -0.904979 0.013916 -0.374045 +v -0.961106 0.016837 -0.186241 +v -0.959657 0.016608 0.203937 +v -0.902136 0.013466 0.391316 +v -0.809216 0.008441 0.563856 +v -0.684468 0.001727 0.714927 +v -0.532686 -0.006419 0.838722 +v -0.359703 -0.015683 0.930485 +v -0.172166 -0.025711 0.986689 +v -0.177735 -0.062765 -0.974897 +v -0.363199 -0.089542 -0.917318 +v -0.533976 -0.114243 -0.824288 +v -0.683502 -0.135920 -0.699381 +v -0.806030 -0.153738 -0.547399 +v -0.896854 -0.167014 -0.374182 +v -0.951032 -0.175466 0.203792 +v -0.894012 -0.167463 0.391180 +v -0.801904 -0.154391 0.563733 +v -0.678250 -0.136750 0.714822 +v -0.527801 -0.115220 0.838640 +v -0.356338 -0.090627 0.930428 +v -0.170451 -0.063916 0.986660 +v -0.168599 -0.099902 -0.974953 +v -0.345278 -0.162389 -0.917427 +v -0.507958 -0.220001 -0.824446 +v -0.650388 -0.270524 -0.699583 +v -0.767092 -0.312015 -0.547637 +v -0.853589 -0.342882 -0.374445 +v -0.906551 -0.361937 -0.186666 +v -0.905102 -0.362166 0.203512 +v -0.850747 -0.343332 0.390916 +v -0.762966 -0.312668 0.563496 +v -0.645136 -0.271354 0.714620 +v -0.501783 -0.220977 0.838481 +v -0.338416 -0.163474 0.930319 +v -0.161315 -0.101053 0.986604 +v 0.015290 -0.034941 -0.994812 +v -0.152393 -0.134543 -0.975033 +v -0.313489 -0.230340 -0.917585 +v -0.461808 -0.318650 -0.824676 +v -0.591650 -0.396080 -0.699875 +v -0.698024 -0.459655 -0.547980 +v -0.776844 -0.506930 -0.374827 +v -0.823631 -0.536319 0.203107 +v -0.774002 -0.507380 0.390534 +v -0.693898 -0.460307 0.563153 +v -0.586399 -0.396911 0.714328 +v -0.455633 -0.319627 0.838252 +v -0.306628 -0.231425 0.930161 +v -0.145109 -0.135695 0.986524 +v -0.129741 -0.165357 -0.975135 +v -0.269055 -0.290783 -0.917786 +v -0.397300 -0.406401 -0.824967 +v -0.509546 -0.507766 -0.700246 +v -0.601481 -0.590982 -0.548416 +v -0.669571 -0.652854 -0.375311 +v -0.711198 -0.691001 -0.187584 +v -0.709750 -0.691230 0.202593 +v -0.666729 -0.653303 0.390050 +v -0.597355 -0.591635 0.562717 +v -0.504295 -0.508596 0.713958 +v -0.391125 -0.407377 0.837961 +v -0.262194 -0.291868 0.929961 +v -0.122457 -0.166508 0.986421 +v -0.567836 -0.820949 0.201990 +v -0.403342 -0.920488 0.201321 +v -0.222589 -0.986023 0.200611 +v -0.032524 -1.015035 0.199888 +v 0.159548 -1.006410 0.199180 +v 0.346248 -0.960479 0.198514 +v 0.520399 -0.879006 0.197915 +v 0.675310 -0.765124 0.197407 +v 0.805028 -0.623208 0.197008 +v 0.904566 -0.458713 0.196735 +v 0.970101 -0.277959 0.196598 +v 0.999114 -0.087893 0.196602 +v 0.990489 0.104181 0.196747 +v 0.944558 0.290881 0.197027 +v 0.863087 0.465034 0.197432 +v 0.749206 0.619946 0.197946 +v 0.607292 0.749663 0.198549 +v 0.442797 0.849202 0.199218 +v 0.262045 0.914737 0.199928 +v 0.071980 0.943750 0.200651 +v -0.120092 0.935124 0.201359 +v -0.306792 0.889193 0.202025 +v -0.480943 0.807721 0.202624 +v -0.635854 0.693839 0.203132 +v -0.765571 0.551923 0.203531 +v -0.865110 0.387428 0.203804 +v -0.930645 0.206674 0.203941 +v -0.959657 0.016608 0.203937 +v -0.951032 -0.175466 0.203792 +v -0.905102 -0.362166 0.203512 +v -0.823631 -0.536319 0.203107 +v -0.709750 -0.691230 0.202593 +v -0.567836 -0.820949 0.201990 +v -0.403342 -0.920488 0.201321 +v -0.222589 -0.986023 0.200611 +v -0.032524 -1.015035 0.199888 +v 0.159548 -1.006410 0.199180 +v 0.346248 -0.960479 0.198514 +v 0.520399 -0.879006 0.197915 +v 0.675310 -0.765124 0.197407 +v 0.805028 -0.623208 0.197008 +v 0.904566 -0.458713 0.196735 +v 0.970101 -0.277959 0.196598 +v 0.999114 -0.087893 0.196602 +v 0.990489 0.104181 0.196747 +v 0.944558 0.290881 0.197027 +v 0.863087 0.465034 0.197432 +v 0.749206 0.619946 0.197946 +v 0.607292 0.749663 0.198549 +v 0.442797 0.849202 0.199218 +v 0.262045 0.914737 0.199928 +v 0.071980 0.943750 0.200651 +v -0.120092 0.935124 0.201359 +v -0.306792 0.889193 0.202025 +v -0.480943 0.807721 0.202624 +v -0.635854 0.693839 0.203132 +v -0.765571 0.551923 0.203531 +v -0.865110 0.387428 0.203804 +v -0.930645 0.206674 0.203941 +v -0.959657 0.016608 0.203937 +v -0.951032 -0.175466 0.203792 +v -0.905102 -0.362166 0.203512 +v -0.823631 -0.536319 0.203107 +v -0.709750 -0.691230 0.202593 +v -0.567836 -0.820949 0.201990 +v -0.403342 -0.920488 0.201321 +v -0.222589 -0.986023 0.200611 +v -0.032524 -1.015035 0.199888 +v 0.159548 -1.006410 0.199180 +v 0.346248 -0.960479 0.198514 +v 0.520399 -0.879006 0.197915 +v 0.675310 -0.765124 0.197407 +v 0.805028 -0.623208 0.197008 +v 0.904566 -0.458713 0.196735 +v 0.970101 -0.277959 0.196598 +v 0.999114 -0.087893 0.196602 +v 0.990489 0.104181 0.196747 +v 0.944558 0.290881 0.197027 +v 0.863087 0.465034 0.197432 +v 0.749206 0.619946 0.197946 +v 0.607292 0.749663 0.198549 +v 0.442797 0.849202 0.199218 +v 0.262045 0.914737 0.199928 +v 0.071980 0.943750 0.200651 +v -0.120092 0.935124 0.201359 +v -0.306792 0.889193 0.202025 +v -0.480943 0.807721 0.202624 +v -0.635854 0.693839 0.203132 +v -0.765571 0.551923 0.203531 +v -0.865110 0.387428 0.203804 +v -0.930645 0.206674 0.203941 +v -0.959657 0.016608 0.203937 +v -0.951032 -0.175466 0.203792 +v -0.905102 -0.362166 0.203512 +v -0.823631 -0.536319 0.203107 +v -0.709750 -0.691230 0.202593 +v -0.567836 -0.820949 0.201990 +v -0.403342 -0.920488 0.201321 +v -0.032524 -1.015035 0.199888 +v 0.970101 -0.277959 0.196598 +v 0.749206 0.619946 0.197946 +v 0.607292 0.749663 0.198549 +v 0.262045 0.914737 0.199928 +v -0.120092 0.935124 0.201359 +v -0.306792 0.889193 0.202025 +v -0.480943 0.807721 0.202624 +v -0.635854 0.693839 0.203132 +v -0.765571 0.551923 0.203531 +v -0.865110 0.387428 0.203804 +v -0.823631 -0.536319 0.203107 +v -0.222589 -0.986023 0.200611 +v 0.159548 -1.006410 0.199180 +v 0.346248 -0.960479 0.198514 +v 0.520399 -0.879006 0.197915 +v 0.675310 -0.765124 0.197407 +v 0.805028 -0.623208 0.197008 +v 0.904566 -0.458713 0.196735 +v 0.999114 -0.087893 0.196602 +v 0.990489 0.104181 0.196747 +v 0.944558 0.290881 0.197027 +v 0.863087 0.465034 0.197432 +v 0.442797 0.849202 0.199218 +v 0.071980 0.943750 0.200651 +v -0.930645 0.206674 0.203941 +v -0.959657 0.016608 0.203937 +v -0.951032 -0.175466 0.203792 +v -0.905102 -0.362166 0.203512 +v -0.709750 -0.691230 0.202593 +v -0.569285 -0.820720 -0.188187 +v -0.404791 -0.920259 -0.188857 +v -0.033973 -1.014806 -0.190289 +v 0.158099 -1.006181 -0.190997 +v 0.673861 -0.764895 -0.192771 +v 0.803579 -0.622979 -0.193169 +v 0.903117 -0.458484 -0.193442 +v 0.943110 0.291110 -0.193151 +v 0.861638 0.465263 -0.192746 +v 0.747757 0.620175 -0.192232 +v 0.441349 0.849431 -0.190960 +v 0.260596 0.914966 -0.190250 +v -0.482392 0.807950 -0.187554 +v -0.637303 0.694068 -0.187045 +v -0.767020 0.552152 -0.186647 +v -0.866559 0.387657 -0.186374 +v -0.932093 0.206903 -0.186237 +v -0.952481 -0.175237 -0.186385 +v -0.825079 -0.536090 -0.187071 +vt 0.438250 0.182161 +vt 0.393752 0.129709 +vt 0.480616 0.104737 +vt 0.496609 0.165881 +vt 0.659488 0.106583 +vt 0.607526 0.157694 +vt 0.536204 0.140776 +vt 0.556563 0.080879 +vt 0.577151 0.212709 +vt 0.556698 0.269278 +vt 0.520314 0.260501 +vt 0.526407 0.200679 +vt 0.541225 0.326558 +vt 0.528339 0.384198 +vt 0.512155 0.380063 +vt 0.515853 0.320275 +vt 0.499144 0.358868 +vt 0.484223 0.298371 +vt 0.511167 0.290653 +vt 0.515893 0.353928 +vt 0.465274 0.239153 +vt 0.505245 0.227937 +vt 0.512069 0.420141 +vt 0.520110 0.417688 +vt 0.516677 0.442031 +vt 0.508745 0.439934 +vt 0.472931 0.203446 +vt 0.457432 0.145204 +vt 0.489928 0.321303 +vt 0.482757 0.262234 +vt 0.533010 0.354177 +vt 0.528307 0.417733 +vt 0.500690 0.440133 +vt 0.495696 0.380597 +vt 0.547046 0.229156 +vt 0.538903 0.291276 +vt 0.584582 0.108643 +vt 0.559871 0.168048 +vt 0.424013 0.220390 +vt 0.390322 0.169423 +vt 0.465000 0.329515 +vt 0.447260 0.274200 +vt 0.549604 0.359563 +vt 0.536319 0.420265 +vt 0.492826 0.442613 +vt 0.479716 0.385747 +vt 0.585821 0.242474 +vt 0.565386 0.300106 +vt 0.661741 0.138767 +vt 0.615044 0.187806 +vt 0.384234 0.248698 +vt 0.342531 0.206999 +vt 0.442409 0.344301 +vt 0.416315 0.295100 +vt 0.564864 0.369751 +vt 0.543819 0.425170 +vt 0.485460 0.447268 +vt 0.464913 0.395236 +vt 0.618239 0.265960 +vt 0.588935 0.316325 +vt 0.706781 0.182838 +vt 0.656048 0.220431 +vt 0.335583 0.124653 +vt 0.286285 0.173430 +vt 0.354236 0.285053 +vt 0.310661 0.252253 +vt 0.423062 0.364721 +vt 0.391075 0.323132 +vt 0.578159 0.384181 +vt 0.550513 0.432235 +vt 0.478869 0.453910 +vt 0.451863 0.408603 +vt 0.643350 0.297086 +vt 0.608567 0.338698 +vt 0.732714 0.233189 +vt 0.684267 0.261122 +vt 0.275753 0.678966 +vt 0.268678 0.621159 +vt 0.332595 0.326772 +vt 0.289590 0.301830 +vt 0.407414 0.389694 +vt 0.371601 0.356503 +vt 0.589067 0.402147 +vt 0.556155 0.441172 +vt 0.473293 0.462278 +vt 0.440988 0.425255 +vt 0.661722 0.333567 +vt 0.623951 0.365870 +vt 0.748196 0.286545 +vt 0.703075 0.306625 +vt 0.263004 0.562933 +vt 0.317557 0.371990 +vt 0.275676 0.353940 +vt 0.395588 0.418142 +vt 0.357415 0.393686 +vt 0.597353 0.422878 +vt 0.560551 0.451626 +vt 0.468927 0.472053 +vt 0.432567 0.444526 +vt 0.674391 0.373639 +vt 0.635166 0.396567 +vt 0.757551 0.341497 +vt 0.715218 0.355009 +vt 0.258269 0.504366 +vt 0.307725 0.419468 +vt 0.266724 0.407615 +vt 0.387541 0.449059 +vt 0.347940 0.433461 +vt 0.602908 0.445588 +vt 0.563562 0.463199 +vt 0.465919 0.482872 +vt 0.426772 0.465716 +vt 0.682290 0.416011 +vt 0.642447 0.429664 +vt 0.762908 0.397383 +vt 0.722466 0.405122 +vt 0.231687 0.340437 +vt 0.224854 0.398408 +vt 0.254173 0.445474 +vt 0.302194 0.468353 +vt 0.261497 0.462297 +vt 0.383190 0.481522 +vt 0.342723 0.474849 +vt 0.605698 0.469497 +vt 0.565099 0.475462 +vt 0.464370 0.494340 +vt 0.423703 0.488107 +vt 0.686064 0.459707 +vt 0.646021 0.464181 +vt 0.765311 0.453847 +vt 0.725827 0.456227 +vt 0.220539 0.456934 +vt 0.250509 0.386245 +vt 0.300509 0.517998 +vt 0.259389 0.517617 +vt 0.382503 0.514662 +vt 0.341539 0.517014 +vt 0.605719 0.493840 +vt 0.565119 0.487969 +vt 0.464340 0.506038 +vt 0.423425 0.510978 +vt 0.686034 0.503930 +vt 0.646024 0.499228 +vt 0.765192 0.510658 +vt 0.725754 0.507782 +vt 0.302644 0.567824 +vt 0.260273 0.573278 +vt 0.385545 0.547618 +vt 0.344432 0.559163 +vt 0.602973 0.517853 +vt 0.563622 0.500266 +vt 0.465841 0.517542 +vt 0.425984 0.533592 +vt 0.682209 0.547926 +vt 0.642462 0.533941 +vt 0.762552 0.567611 +vt 0.722254 0.559289 +vt 0.309027 0.617196 +vt 0.264496 0.628959 +vt 0.392493 0.579475 +vt 0.351745 0.600429 +vt 0.597472 0.540758 +vt 0.560651 0.511903 +vt 0.468841 0.528422 +vt 0.431407 0.555192 +vt 0.674287 0.590873 +vt 0.635216 0.567412 +vt 0.756960 0.624452 +vt 0.714890 0.610178 +vt 0.243834 0.266647 +vt 0.240431 0.206208 +vt 0.320667 0.665272 +vt 0.273052 0.684200 +vt 0.403604 0.609206 +vt 0.364149 0.639758 +vt 0.589254 0.561759 +vt 0.556296 0.522447 +vt 0.473257 0.538265 +vt 0.439678 0.574994 +vt 0.661651 0.631749 +vt 0.624073 0.598625 +vt 0.747383 0.680773 +vt 0.702683 0.659660 +vt 0.236241 0.145306 +vt 0.339376 0.710769 +vt 0.288067 0.738204 +vt 0.419140 0.635632 +vt 0.382622 0.675753 +vt 0.578431 0.580038 +vt 0.550696 0.531487 +vt 0.478952 0.546678 +vt 0.450702 0.592195 +vt 0.643404 0.669188 +vt 0.608810 0.626405 +vt 0.731736 0.735824 +vt 0.683922 0.706496 +vt 0.222082 0.695047 +vt 0.229112 0.755097 +vt 0.225093 0.083963 +vt 0.368020 0.751581 +vt 0.313935 0.789370 +vt 0.439194 0.657409 +vt 0.408268 0.706530 +vt 0.565235 0.594791 +vt 0.544041 0.538663 +vt 0.485730 0.553316 +vt 0.464238 0.606002 +vt 0.618553 0.701329 +vt 0.589356 0.649409 +vt 0.705838 0.788061 +vt 0.655971 0.748630 +vt 0.242947 0.814699 +vt 0.410235 0.784227 +vt 0.359623 0.834106 +vt 0.463432 0.673121 +vt 0.441736 0.729668 +vt 0.550080 0.605277 +vt 0.536577 0.543672 +vt 0.493335 0.557892 +vt 0.479847 0.615695 +vt 0.586547 0.725770 +vt 0.566032 0.666211 +vt 0.661474 0.834012 +vt 0.615614 0.782655 +vt 0.467791 0.803629 +vt 0.439420 0.864199 +vt 0.490820 0.681485 +vt 0.482092 0.742518 +vt 0.533583 0.610903 +vt 0.528592 0.546295 +vt 0.501464 0.560198 +vt 0.496859 0.620700 +vt 0.548280 0.739857 +vt 0.539786 0.675501 +vt 0.586508 0.865808 +vt 0.561504 0.803590 +vt 0.534602 0.804848 +vt 0.550219 0.866655 +vt 0.519558 0.681668 +vt 0.525825 0.743080 +vt 0.516540 0.611308 +vt 0.520412 0.546410 +vt 0.509773 0.560126 +vt 0.514412 0.620684 +vt 0.506922 0.741531 +vt 0.512244 0.676402 +vt 0.485320 0.870954 +vt 0.499263 0.806494 +vt 0.360675 0.921110 +vt 0.597070 0.926593 +vt 0.596536 0.787112 +vt 0.644366 0.839022 +vt 0.547433 0.673560 +vt 0.567661 0.731066 +vt 0.499827 0.606430 +vt 0.512375 0.544003 +vt 0.517906 0.557669 +vt 0.531548 0.615611 +vt 0.467162 0.730371 +vt 0.485403 0.668743 +vt 0.398652 0.846104 +vt 0.441250 0.790283 +vt 0.643697 0.754632 +vt 0.700166 0.793774 +vt 0.572438 0.657819 +vt 0.603214 0.708082 +vt 0.484285 0.596520 +vt 0.504812 0.539170 +vt 0.525514 0.552931 +vt 0.547357 0.605757 +vt 0.432902 0.707830 +vt 0.461076 0.653118 +vt 0.345076 0.802447 +vt 0.396125 0.758758 +vt 0.675718 0.712759 +vt 0.730591 0.740698 +vt 0.593263 0.635652 +vt 0.630685 0.676716 +vt 0.470605 0.582098 +vt 0.498029 0.532110 +vt 0.532281 0.546113 +vt 0.561102 0.591659 +vt 0.405802 0.676407 +vt 0.440471 0.630693 +vt 0.314103 0.749853 +vt 0.364394 0.717126 +vt 0.696147 0.665420 +vt 0.747191 0.684126 +vt 0.609362 0.608500 +vt 0.650332 0.639532 +vt 0.459277 0.563877 +vt 0.492285 0.523114 +vt 0.537943 0.537505 +vt 0.572272 0.574039 +vt 0.385702 0.638654 +vt 0.424119 0.602886 +vt 0.295718 0.693036 +vt 0.343058 0.669387 +vt 0.708306 0.615056 +vt 0.755832 0.625963 +vt 0.620727 0.577788 +vt 0.663224 0.598616 +vt 0.450604 0.542679 +vt 0.487789 0.512545 +vt 0.542293 0.527461 +vt 0.580575 0.553718 +vt 0.371704 0.596681 +vt 0.412075 0.571126 +vt 0.284618 0.634133 +vt 0.329200 0.618088 +vt 0.802650 0.693604 +vt 0.805171 0.630363 +vt 0.714403 0.563189 +vt 0.759328 0.567195 +vt 0.627599 0.544812 +vt 0.670441 0.555557 +vt 0.444740 0.519368 +vt 0.484696 0.500819 +vt 0.545188 0.516387 +vt 0.585887 0.531546 +vt 0.362875 0.552111 +vt 0.404172 0.536721 +vt 0.278176 0.574237 +vt 0.320837 0.564821 +vt 0.804922 0.567205 +vt 0.715699 0.510860 +vt 0.758995 0.508449 +vt 0.630264 0.510724 +vt 0.672774 0.511595 +vt 0.441755 0.494812 +vt 0.483107 0.488388 +vt 0.546542 0.504714 +vt 0.588189 0.508372 +vt 0.358543 0.506195 +vt 0.400214 0.500837 +vt 0.275111 0.513995 +vt 0.316812 0.510645 +vt 0.802599 0.504363 +vt 0.712772 0.458885 +vt 0.755325 0.450215 +vt 0.628939 0.476563 +vt 0.670665 0.467762 +vt 0.441672 0.469868 +vt 0.483071 0.475724 +vt 0.546327 0.492891 +vt 0.587519 0.485021 +vt 0.358365 0.459961 +vt 0.400082 0.464534 +vt 0.274886 0.453860 +vt 0.316602 0.456352 +vt 0.798369 0.442045 +vt 0.705665 0.408030 +vt 0.748238 0.392973 +vt 0.623739 0.443316 +vt 0.664226 0.425023 +vt 0.444496 0.445381 +vt 0.484591 0.463304 +vt 0.544566 0.481363 +vt 0.583950 0.462293 +vt 0.362339 0.414353 +vt 0.403777 0.428822 +vt 0.277485 0.394214 +vt 0.320196 0.402634 +vt 0.677291 0.782374 +vt 0.658376 0.839784 +vt 0.693946 0.359145 +vt 0.737106 0.337298 +vt 0.614685 0.411966 +vt 0.653282 0.384380 +vt 0.450210 0.422192 +vt 0.487619 0.451595 +vt 0.541327 0.470560 +vt 0.577578 0.440972 +vt 0.370806 0.370353 +vt 0.411428 0.394730 +vt 0.283403 0.335457 +vt 0.328098 0.350228 +vt 0.627628 0.892175 +vt 0.676695 0.313318 +vt 0.720590 0.284013 +vt 0.601756 0.383536 +vt 0.637429 0.346984 +vt 0.458757 0.401145 +vt 0.492060 0.441043 +vt 0.536731 0.460888 +vt 0.568550 0.421814 +vt 0.384445 0.329118 +vt 0.423244 0.363365 +vt 0.293870 0.278123 +vt 0.341446 0.300077 +vt 0.573952 0.933686 +vt 0.652498 0.272065 +vt 0.696294 0.234453 +vt 0.584990 0.359102 +vt 0.616162 0.314214 +vt 0.469988 0.383068 +vt 0.497762 0.432059 +vt 0.530942 0.452713 +vt 0.557086 0.405544 +vt 0.404213 0.292135 +vt 0.439413 0.335956 +vt 0.311435 0.223111 +vt 0.362224 0.253590 +vt 0.619672 0.237558 +vt 0.660305 0.190967 +vt 0.564617 0.339767 +vt 0.589146 0.287714 +vt 0.483612 0.368748 +vt 0.504519 0.424997 +vt 0.524172 0.446345 +vt 0.543523 0.392822 +vt 0.431071 0.261351 +vt 0.459907 0.313844 +vt 0.341329 0.172245 +vt 0.393416 0.213056 +vt 0.524230 0.481846 +vt 0.505289 0.499959 +vt 0.716580 0.471300 +vt 0.720692 0.407605 +vt 0.297856 0.792313 +vt 0.317042 0.846454 +vt 0.689991 0.722315 +vt 0.727890 0.280471 +vt 0.731397 0.217289 +vt 0.348325 0.896246 +vt 0.402986 0.935669 +vt 0.699167 0.660689 +vt 0.735487 0.154491 +vt 0.247116 0.326648 +vt 0.706197 0.598081 +vt 0.744165 0.092163 +vt 0.488860 0.951554 +vt 0.711848 0.534863 +vt 0.285011 0.736160 +vt 1.225093 0.083963 +vt 0.724400 0.343948 +vt 0.773795 0.158170 +vt 0.788466 0.216076 +vt 0.796411 0.274716 +vt 0.800960 0.333743 +vt 0.803463 0.393054 +vt 0.804519 0.452628 +vt 0.802975 0.572602 +vt 0.800114 0.633001 +vt 0.795158 0.693609 +vt 0.786724 0.754255 +vt 0.233314 0.452583 +vt 0.234465 0.389481 +vt 0.237256 0.326928 +vt 0.242409 0.265075 +vt 0.426641 0.088579 +vt 0.258778 0.227203 +vt 0.242216 0.283222 +vt 0.218157 0.515921 +vt 0.217490 0.575311 +vt 0.218632 0.635051 +vt 0.273379 0.872324 +vt 0.736781 0.878589 +vt 0.779085 0.818830 +vt 0.795566 0.756616 +vt 0.792020 0.380478 +vt 0.782910 0.319943 +vt 0.769712 0.260872 +vt 0.749733 0.204055 +vt 0.717215 0.151203 +vt 0.088482 0.960235 +vt 0.115179 0.963937 +vt 0.143520 0.965825 +vt 0.172416 0.965825 +vt 0.200757 0.963937 +vt 0.227454 0.960235 +vt 0.251481 0.954860 +vt 0.271914 0.948018 +vt 0.287968 0.939973 +vt 0.299026 0.931035 +vt 0.304663 0.921545 +vt 0.304663 0.911870 +vt 0.299026 0.902381 +vt 0.287968 0.893442 +vt 0.271914 0.885397 +vt 0.251481 0.878556 +vt 0.227454 0.873181 +vt 0.200758 0.869478 +vt 0.172416 0.867590 +vt 0.143520 0.867590 +vt 0.115179 0.869478 +vt 0.088482 0.873181 +vt 0.064455 0.878556 +vt 0.044023 0.885397 +vt 0.027969 0.893442 +vt 0.016910 0.902381 +vt 0.011273 0.911870 +vt 0.011273 0.921545 +vt 0.016910 0.931035 +vt 0.027969 0.939973 +vt 0.044023 0.948018 +vt 0.064455 0.954860 +vt 0.026639 0.890276 +vt 0.042857 0.881942 +vt 0.063499 0.874854 +vt 0.087771 0.869285 +vt 0.114741 0.865449 +vt 0.143372 0.863494 +vt 0.172564 0.863494 +vt 0.201195 0.865449 +vt 0.228165 0.869285 +vt 0.252437 0.874854 +vt 0.273078 0.881942 +vt 0.289297 0.890276 +vt 0.300468 0.899537 +vt 0.306163 0.909368 +vt 0.306163 0.919391 +vt 0.300468 0.929222 +vt 0.289297 0.938483 +vt 0.273078 0.946817 +vt 0.252437 0.953905 +vt 0.228164 0.959474 +vt 0.201195 0.963310 +vt 0.172564 0.965265 +vt 0.143372 0.965265 +vt 0.114741 0.963310 +vt 0.087771 0.959474 +vt 0.063499 0.953905 +vt 0.042857 0.946817 +vt 0.026639 0.938483 +vt 0.015468 0.929222 +vt 0.009773 0.919391 +vt 0.009773 0.909368 +vt 0.015468 0.899537 +vt 0.309551 0.088675 +vt 0.432561 0.045895 +vt 0.653135 0.054300 +vt 0.742321 0.102234 +vt 0.804359 0.512475 +vt 0.771461 0.814475 +vt 0.739493 0.872817 +vt 0.652968 0.922873 +vt 0.444522 0.933687 +vt 0.317193 0.890918 +vt 0.273641 0.832725 +vt 0.254425 0.770807 +vt 0.244271 0.707568 +vt 0.238454 0.643806 +vt 0.235139 0.579905 +vt 0.233532 0.516105 +vt 0.251609 0.204160 +vt 0.269226 0.144737 +vn -0.455300 -0.755600 0.470900 +vn -0.496700 -0.818900 -0.287600 +vn -0.403300 -0.662300 -0.631500 +vn -0.248200 -0.404300 -0.880300 +vn -0.241700 -0.405300 0.881600 +vn -0.398600 -0.663000 0.633700 +vn -0.458800 -0.755100 -0.468400 +vn -0.332200 -0.543900 -0.770600 +vn -0.147400 -0.250000 0.957000 +vn -0.154500 -0.248900 -0.956100 +vn -0.326500 -0.544800 0.772400 +vn -0.302700 -0.829700 -0.469000 +vn -0.219700 -0.597700 -0.771000 +vn -0.095800 -0.274700 0.956800 +vn -0.102900 -0.273500 -0.956300 +vn -0.214000 -0.598600 0.772000 +vn -0.299200 -0.830300 0.470300 +vn -0.266300 -0.727800 -0.632000 +vn -0.164600 -0.444300 -0.880600 +vn -0.158000 -0.445400 0.881300 +vn -0.261600 -0.728500 0.633100 +vn -0.135000 -0.872500 -0.469600 +vn -0.098900 -0.628500 -0.771500 +vn -0.040400 -0.288800 0.956500 +vn -0.047500 -0.287700 -0.956500 +vn -0.093100 -0.629400 0.771500 +vn -0.131500 -0.873000 0.469600 +vn -0.119200 -0.765300 -0.632600 +vn -0.074700 -0.467200 -0.881000 +vn -0.068100 -0.468300 0.881000 +vn -0.114500 -0.766000 0.632500 +vn 0.037900 -0.881700 -0.470300 +vn 0.025700 -0.635100 -0.772000 +vn 0.016600 -0.291800 0.956300 +vn 0.009500 -0.290700 -0.956800 +vn 0.031400 -0.636000 0.771000 +vn 0.041300 -0.882300 0.469000 +vn 0.041900 -0.956200 -0.289700 +vn 0.032400 -0.773400 -0.633100 +vn 0.018000 -0.472200 -0.881300 +vn 0.024500 -0.473200 0.880600 +vn 0.037100 -0.774100 0.632000 +vn 0.209200 -0.857000 -0.470900 +vn 0.149100 -0.617300 -0.772400 +vn 0.073200 -0.283700 0.956100 +vn 0.066100 -0.282600 -0.957000 +vn 0.154900 -0.618300 0.770600 +vn 0.212600 -0.857600 0.468300 +vn 0.182700 -0.751700 -0.633700 +vn 0.109800 -0.459000 -0.881700 +vn 0.116300 -0.460000 0.880300 +vn 0.187400 -0.752500 0.631400 +vn 0.000000 0.000000 1.000000 +vn 0.372400 -0.799400 -0.471500 +vn 0.266700 -0.575800 -0.772800 +vn 0.127100 -0.264700 0.955900 +vn 0.120000 -0.263500 -0.957200 +vn 0.272500 -0.576700 0.770200 +vn 0.375800 -0.800000 0.467800 +vn 0.325800 -0.701200 -0.634200 +vn 0.197200 -0.428100 -0.882000 +vn 0.203800 -0.429100 0.880000 +vn 0.330500 -0.701900 0.630900 +vn -0.246400 0.171100 -0.953900 +vn 0.521200 -0.711100 -0.472000 +vn 0.374000 -0.512200 -0.773200 +vn 0.176300 -0.235500 0.955800 +vn 0.169100 -0.234400 -0.957300 +vn 0.379700 -0.513100 0.769800 +vn 0.524700 -0.711600 0.467300 +vn 0.456400 -0.623700 -0.634600 +vn 0.277000 -0.380700 -0.882200 +vn 0.283500 -0.381800 0.879700 +vn 0.461100 -0.624400 0.630500 +vn -0.848000 0.530000 0.000000 +vn 0.649900 -0.595400 -0.472400 +vn 0.466700 -0.428800 -0.773500 +vn 0.218800 -0.197300 0.955600 +vn 0.211700 -0.196200 -0.957500 +vn 0.472500 -0.429700 0.769500 +vn 0.653400 -0.595900 0.466900 +vn 0.705500 -0.645700 -0.292000 +vn 0.569300 -0.522200 -0.635000 +vn 0.346000 -0.318700 -0.882500 +vn 0.352500 -0.319800 0.879500 +vn 0.574000 -0.522900 0.630100 +vn 0.753600 -0.456800 -0.472700 +vn 0.541500 -0.328900 -0.773700 +vn 0.253000 -0.151500 0.955500 +vn 0.245900 -0.150400 -0.957600 +vn 0.547200 -0.329800 0.769300 +vn 0.757100 -0.457300 0.466600 +vn 0.818000 -0.495400 -0.292300 +vn 0.660300 -0.400600 -0.635300 +vn 0.401500 -0.244400 -0.882600 +vn 0.408100 -0.245500 0.879300 +vn 0.665000 -0.401300 0.629900 +vn 0.828200 -0.300700 -0.472900 +vn 0.595300 -0.216400 -0.773800 +vn 0.277700 -0.099900 0.955500 +vn 0.270600 -0.098800 -0.957600 +vn 0.601000 -0.217300 0.769200 +vn 0.831700 -0.301200 0.466400 +vn 0.725800 -0.263600 -0.635400 +vn 0.441600 -0.160800 -0.882700 +vn 0.448100 -0.161800 0.879200 +vn 0.730500 -0.264400 0.629700 +vn 0.871000 -0.132900 -0.472900 +vn 0.626100 -0.095600 -0.773900 +vn 0.291800 -0.044600 0.955400 +vn 0.284700 -0.043400 -0.957600 +vn 0.631800 -0.096500 0.769100 +vn 0.874500 -0.133500 0.466300 +vn 0.763300 -0.116500 -0.635500 +vn 0.464500 -0.070900 -0.882700 +vn 0.471000 -0.071900 0.879200 +vn 0.768000 -0.117200 0.629600 +vn 0.880200 0.039900 -0.472900 +vn 0.632700 0.029000 -0.773800 +vn 0.294800 0.012500 0.955500 +vn 0.287700 0.013600 -0.957600 +vn 0.638400 0.028100 0.769200 +vn 0.883700 0.039300 0.466400 +vn 0.771400 0.035100 -0.635400 +vn 0.469400 0.021700 -0.882700 +vn 0.476000 0.020700 0.879200 +vn 0.776100 0.034400 0.629700 +vn 0.855600 0.211200 -0.472700 +vn 0.614900 0.152400 -0.773700 +vn 0.286700 0.069100 0.955500 +vn 0.279600 0.070200 -0.957600 +vn 0.620700 0.151500 0.769300 +vn 0.859000 0.210600 0.466600 +vn 0.749700 0.185400 -0.635200 +vn 0.456200 0.113600 -0.882600 +vn 0.462700 0.112500 0.879300 +vn 0.754400 0.184700 0.629900 +vn 0.797900 0.374400 -0.472400 +vn 0.573400 0.270000 -0.773500 +vn 0.267600 0.123000 0.955600 +vn 0.260500 0.124100 -0.957500 +vn 0.579100 0.269100 0.769500 +vn 0.801400 0.373800 0.466900 +vn 0.866100 0.405800 -0.292000 +vn 0.699200 0.328600 -0.635000 +vn 0.425300 0.201000 -0.882400 +vn 0.431900 0.200000 0.879500 +vn 0.703900 0.327800 0.630100 +vn 0.709600 0.523200 -0.472000 +vn 0.509700 0.377300 -0.773200 +vn 0.238500 0.172100 0.955800 +vn 0.231400 0.173300 -0.957300 +vn 0.515500 0.376400 0.769800 +vn 0.713100 0.522700 0.467300 +vn 0.770300 0.567200 -0.291500 +vn 0.621700 0.459100 -0.634600 +vn 0.378000 0.280800 -0.882200 +vn 0.384500 0.279700 0.879700 +vn 0.626400 0.458400 0.630500 +vn 0.593900 0.651900 -0.471500 +vn 0.426400 0.470100 -0.772800 +vn 0.200300 0.214700 0.955900 +vn 0.193200 0.215800 -0.957100 +vn 0.432100 0.469200 0.770200 +vn 0.597400 0.651400 0.467800 +vn 0.520200 0.572000 -0.634200 +vn 0.316000 0.349800 -0.881900 +vn 0.322500 0.348700 0.880000 +vn 0.524900 0.571300 0.631000 +vn 0.455300 0.755600 -0.470900 +vn 0.326500 0.544800 -0.772400 +vn 0.154500 0.248900 0.956100 +vn 0.147400 0.250000 -0.957000 +vn 0.332200 0.543900 0.770600 +vn 0.458800 0.755100 0.468400 +vn 0.398600 0.663000 -0.633700 +vn 0.241700 0.405300 -0.881600 +vn 0.248200 0.404300 0.880300 +vn 0.403300 0.662300 0.631500 +vn 0.299200 0.830300 -0.470300 +vn 0.214000 0.598600 -0.772000 +vn 0.102900 0.273500 0.956300 +vn 0.095800 0.274700 -0.956800 +vn 0.219700 0.597700 0.771000 +vn 0.302700 0.829700 0.469000 +vn 0.325200 0.900200 -0.289700 +vn 0.261600 0.728500 -0.633100 +vn 0.158000 0.445400 -0.881300 +vn 0.164600 0.444300 0.880600 +vn 0.266300 0.727800 0.632000 +vn 0.131500 0.873000 -0.469600 +vn 0.093100 0.629400 -0.771500 +vn 0.047600 0.287700 0.956500 +vn 0.040400 0.288800 -0.956500 +vn 0.098900 0.628500 0.771500 +vn 0.135000 0.872500 0.469600 +vn 0.114500 0.766000 -0.632500 +vn 0.068100 0.468300 -0.881000 +vn 0.074700 0.467200 0.881000 +vn 0.119200 0.765300 0.632600 +vn -0.041300 0.882300 -0.469000 +vn -0.031400 0.636000 -0.771000 +vn -0.009500 0.290700 0.956800 +vn -0.016600 0.291800 -0.956300 +vn -0.025700 0.635100 0.772000 +vn -0.037900 0.881700 0.470300 +vn -0.037100 0.774100 -0.632000 +vn -0.024500 0.473200 -0.880600 +vn -0.018000 0.472200 0.881300 +vn -0.032400 0.773400 0.633100 +vn -0.212600 0.857600 -0.468300 +vn -0.154900 0.618300 -0.770600 +vn -0.066100 0.282600 0.957000 +vn -0.073200 0.283700 -0.956100 +vn -0.149100 0.617300 0.772400 +vn -0.209200 0.857000 0.470900 +vn -0.187400 0.752500 -0.631400 +vn -0.116300 0.460000 -0.880300 +vn -0.109800 0.459000 0.881700 +vn -0.182700 0.751700 0.633700 +vn -0.375800 0.800000 -0.467800 +vn -0.272500 0.576700 -0.770200 +vn -0.120000 0.263500 0.957200 +vn -0.127100 0.264700 -0.955900 +vn -0.266700 0.575800 0.772800 +vn -0.372400 0.799400 0.471500 +vn -0.330500 0.701900 -0.630900 +vn -0.203800 0.429100 -0.880000 +vn -0.197200 0.428100 0.882000 +vn -0.325800 0.701200 0.634200 +vn -0.524700 0.711600 -0.467300 +vn -0.379700 0.513100 -0.769800 +vn -0.169100 0.234400 0.957300 +vn -0.176300 0.235500 -0.955800 +vn -0.374000 0.512200 0.773200 +vn -0.521200 0.711100 0.472000 +vn -0.568100 0.771500 -0.286400 +vn -0.461100 0.624400 -0.630500 +vn -0.283500 0.381800 -0.879700 +vn -0.277000 0.380700 0.882200 +vn -0.456400 0.623700 0.634600 +vn -0.653400 0.595900 -0.466900 +vn -0.472500 0.429700 -0.769500 +vn -0.211700 0.196200 0.957500 +vn -0.218800 0.197300 -0.955600 +vn -0.466700 0.428800 0.773500 +vn -0.649900 0.595400 0.472400 +vn -0.707700 0.646100 -0.286000 +vn -0.574000 0.522900 -0.630100 +vn -0.352500 0.319800 -0.879500 +vn -0.346000 0.318700 0.882500 +vn -0.569300 0.522200 0.635000 +vn -0.757100 0.457300 -0.466600 +vn -0.547200 0.329800 -0.769300 +vn -0.245900 0.150400 0.957600 +vn -0.253000 0.151500 -0.955500 +vn -0.541500 0.328900 0.773700 +vn -0.753600 0.456800 0.472700 +vn -0.820100 0.495800 -0.285700 +vn -0.665000 0.401300 -0.629900 +vn -0.408100 0.245500 -0.879300 +vn -0.401500 0.244400 0.882600 +vn -0.660300 0.400600 0.635300 +vn -0.831700 0.301200 -0.466400 +vn -0.601000 0.217300 -0.769200 +vn -0.270600 0.098800 0.957600 +vn -0.277700 0.099900 -0.955500 +vn -0.595300 0.216400 0.773800 +vn -0.828200 0.300700 0.472900 +vn -0.901100 0.326500 -0.285500 +vn -0.730500 0.264400 -0.629700 +vn -0.448100 0.161800 -0.879200 +vn -0.441600 0.160800 0.882700 +vn -0.725800 0.263600 0.635400 +vn -0.874500 0.133500 -0.466300 +vn -0.631800 0.096500 -0.769100 +vn -0.284700 0.043400 0.957600 +vn -0.291800 0.044600 -0.955400 +vn -0.626100 0.095500 0.773900 +vn -0.871000 0.132900 0.472900 +vn -0.768000 0.117200 -0.629600 +vn -0.471000 0.071900 -0.879200 +vn -0.464500 0.070900 0.882700 +vn -0.763300 0.116500 0.635500 +vn -0.883700 -0.039300 -0.466400 +vn -0.638400 -0.028100 -0.769200 +vn -0.287700 -0.013600 0.957600 +vn -0.294800 -0.012500 -0.955500 +vn -0.632700 -0.029000 0.773800 +vn -0.880200 -0.039900 0.472900 +vn -0.776100 -0.034400 -0.629700 +vn -0.476000 -0.020700 -0.879200 +vn -0.469400 -0.021700 0.882700 +vn -0.771400 -0.035100 0.635400 +vn -0.859000 -0.210600 -0.466600 +vn -0.620700 -0.151500 -0.769300 +vn -0.279600 -0.070200 0.957600 +vn -0.286700 -0.069100 -0.955500 +vn -0.614900 -0.152400 0.773700 +vn -0.855600 -0.211200 0.472700 +vn -0.754400 -0.184700 -0.629900 +vn -0.462700 -0.112500 -0.879300 +vn -0.456200 -0.113600 0.882600 +vn -0.749700 -0.185400 0.635200 +vn -0.801400 -0.373800 -0.466900 +vn -0.579100 -0.269100 -0.769500 +vn -0.260500 -0.124100 0.957500 +vn -0.267600 -0.123000 -0.955600 +vn -0.573400 -0.270000 0.773500 +vn -0.797900 -0.374400 0.472400 +vn -0.703900 -0.327800 -0.630100 +vn -0.431900 -0.200000 -0.879500 +vn -0.425300 -0.201000 0.882400 +vn -0.699200 -0.328600 0.635000 +vn -0.713100 -0.522700 -0.467300 +vn -0.515500 -0.376400 -0.769800 +vn -0.231400 -0.173300 0.957300 +vn -0.238500 -0.172100 -0.955800 +vn -0.509700 -0.377300 0.773200 +vn -0.709600 -0.523200 0.472000 +vn -0.626400 -0.458400 -0.630500 +vn -0.384500 -0.279700 -0.879700 +vn -0.378000 -0.280800 0.882200 +vn -0.621700 -0.459100 0.634600 +vn -0.047300 -0.084800 0.995300 +vn -0.054700 -0.083700 -0.995000 +vn -0.029900 -0.093200 0.995200 +vn -0.037300 -0.092000 -0.995100 +vn -0.011200 -0.097900 0.995100 +vn -0.018500 -0.096800 -0.995100 +vn 0.008100 -0.099000 0.995100 +vn 0.000700 -0.097800 -0.995200 +vn 0.027200 -0.096200 0.995000 +vn 0.019800 -0.095100 -0.995300 +vn 0.045400 -0.089800 0.994900 +vn 0.038000 -0.088600 -0.995300 +vn 0.062000 -0.079900 0.994900 +vn 0.054600 -0.078800 -0.995400 +vn 0.076400 -0.067000 0.994800 +vn 0.069000 -0.065900 -0.995400 +vn 0.088000 -0.051600 0.994800 +vn 0.080600 -0.050400 -0.995500 +vn 0.096300 -0.034200 0.994800 +vn 0.088900 -0.033000 -0.995500 +vn 0.101100 -0.015400 0.994800 +vn 0.093700 -0.014300 -0.995500 +vn 0.102100 0.003800 0.994800 +vn 0.094700 0.005000 -0.995500 +vn 0.099300 0.022900 0.994800 +vn 0.091900 0.024100 -0.995500 +vn 0.092900 0.041100 0.994800 +vn 0.085500 0.042300 -0.995400 +vn 0.083000 0.057800 0.994900 +vn 0.075600 0.058900 -0.995400 +vn 0.070100 0.072100 0.994900 +vn 0.062800 0.073300 -0.995300 +vn 0.054700 0.083700 0.995000 +vn 0.047300 0.084800 -0.995300 +vn 0.037300 0.092000 0.995100 +vn 0.029900 0.093200 -0.995200 +vn 0.018600 0.096800 0.995100 +vn 0.011200 0.097900 -0.995100 +vn -0.000700 0.097800 0.995200 +vn -0.008100 0.099000 -0.995100 +vn -0.019800 0.095100 0.995300 +vn -0.027200 0.096200 -0.995000 +vn -0.038000 0.088600 0.995300 +vn -0.045400 0.089800 -0.994900 +vn -0.054600 0.078800 0.995400 +vn -0.062000 0.079900 -0.994900 +vn -0.069000 0.065900 0.995400 +vn -0.076400 0.067000 -0.994800 +vn -0.080600 0.050400 0.995500 +vn -0.088000 0.051600 -0.994800 +vn -0.088900 0.033000 0.995500 +vn -0.096300 0.034200 -0.994800 +vn -0.093700 0.014300 0.995500 +vn -0.101100 0.015400 -0.994800 +vn -0.094700 -0.005000 0.995500 +vn -0.102100 -0.003800 -0.994800 +vn -0.091900 -0.024100 0.995500 +vn -0.099300 -0.022900 -0.994800 +vn -0.085500 -0.042300 0.995400 +vn -0.092900 -0.041100 -0.994800 +vn -0.075700 -0.058900 0.995400 +vn -0.083000 -0.057800 -0.994900 +vn -0.597400 -0.651400 -0.467800 +vn -0.432100 -0.469200 -0.770200 +vn -0.193200 -0.215800 0.957100 +vn -0.200300 -0.214600 -0.955900 +vn -0.426400 -0.470100 0.772800 +vn -0.593900 -0.651900 0.471500 +vn -0.524900 -0.571300 -0.631000 +vn -0.062800 -0.073300 0.995300 +vn -0.322500 -0.348700 -0.880000 +vn -0.316000 -0.349800 0.881900 +vn -0.070100 -0.072100 -0.994900 +vn -0.520200 -0.572000 0.634200 +vn 0.229800 -0.929800 0.287600 +vn 0.406700 -0.867300 0.287000 +vn 0.568100 -0.771500 0.286400 +vn 0.707700 -0.646100 0.286000 +vn 0.820100 -0.495800 0.285700 +vn 0.957400 0.042800 0.285500 +vn 0.930700 0.228500 0.285700 +vn 0.868200 0.405500 0.286000 +vn -0.945300 0.144300 0.292600 +vn -0.955300 -0.043100 0.292500 +vn -0.928500 -0.228900 0.292300 +vn -0.327400 -0.899800 -0.288300 +vn -0.145500 -0.946200 -0.289000 +vn 0.227600 -0.929400 -0.290400 +vn 0.404600 -0.867000 -0.291000 +vn 0.566000 -0.771200 -0.291600 +vn 0.898900 -0.326100 -0.292500 +vn 0.945300 -0.144300 -0.292600 +vn 0.955300 0.043100 -0.292500 +vn 0.928500 0.228900 -0.292300 +vn 0.644800 0.706800 -0.291000 +vn 0.494500 0.819200 -0.290400 +vn 0.143400 0.946500 -0.289000 +vn -0.044000 0.956500 -0.288300 +vn -0.229800 0.929800 -0.287600 +vn -0.406700 0.867300 -0.287000 +vn -0.947400 0.144600 -0.285400 +vn -0.957400 -0.042800 -0.285500 +vn -0.930700 -0.228500 -0.285700 +vn -0.868200 -0.405500 -0.286000 +vn -0.772400 -0.566900 -0.286500 +vn -0.647000 -0.706400 -0.287000 +vn -0.824000 0.566500 0.000000 +vn -0.003700 0.000600 -1.000000 +vn 0.003700 -0.000600 1.000000 +vn -0.494500 -0.819200 0.290400 +vn -0.325200 -0.900200 0.289700 +vn -0.143400 -0.946500 0.289000 +vn 0.044000 -0.956500 0.288300 +vn 0.901100 -0.326500 0.285500 +vn 0.947400 -0.144600 0.285400 +vn 0.772400 0.566900 0.286500 +vn 0.647000 0.706400 0.287000 +vn 0.496700 0.818900 0.287600 +vn 0.327400 0.899800 0.288300 +vn 0.145500 0.946200 0.289000 +vn -0.041900 0.956200 0.289700 +vn -0.227600 0.929400 0.290400 +vn -0.404600 0.867000 0.291000 +vn -0.566000 0.771200 0.291600 +vn -0.705500 0.645700 0.292000 +vn -0.818000 0.495400 0.292300 +vn -0.898900 0.326100 0.292500 +vn -0.866100 -0.405800 0.292000 +vn -0.770300 -0.567200 0.291500 +vn -0.644800 -0.706800 0.291000 +s off +f 9/1/1 8/2/1 21/3/1 22/4/1 +f 560/5/2 6/6/2 19/7/2 561/8/2 +f 5/9/3 4/10/3 17/11/3 18/12/3 +f 3/13/4 2/14/4 15/15/4 16/16/4 +f 12/17/5 11/18/5 24/19/5 25/20/5 +f 10/21/6 9/1/6 22/4/6 23/22/6 +f 6/6/7 5/9/7 18/12/7 19/7/7 +f 4/10/8 3/13/8 16/16/8 17/11/8 +f 13/23/9 12/17/9 25/20/9 26/24/9 +f 2/14/10 1/25/10 14/26/10 15/15/10 +f 11/18/11 10/21/11 23/22/11 24/19/11 +f 19/7/12 18/12/12 31/27/12 32/28/12 +f 17/11/13 16/16/13 29/29/13 30/30/13 +f 26/24/14 25/20/14 39/31/14 40/32/14 +f 15/15/15 14/26/15 27/33/15 28/34/15 +f 24/19/16 23/22/16 37/35/16 38/36/16 +f 22/4/17 21/3/17 35/37/17 36/38/17 +f 18/12/18 17/11/18 30/30/18 31/27/18 +f 16/16/19 15/15/19 28/34/19 29/29/19 +f 25/20/20 24/19/20 38/36/20 39/31/20 +f 23/22/21 22/4/21 36/38/21 37/35/21 +f 32/28/22 31/27/22 45/39/22 46/40/22 +f 30/30/23 29/29/23 43/41/23 44/42/23 +f 40/32/24 39/31/24 52/43/24 53/44/24 +f 28/34/25 27/33/25 41/45/25 42/46/25 +f 38/36/26 37/35/26 50/47/26 51/48/26 +f 36/38/27 35/37/27 48/49/27 49/50/27 +f 31/27/28 30/30/28 44/42/28 45/39/28 +f 29/29/29 28/34/29 42/46/29 43/41/29 +f 39/31/30 38/36/30 51/48/30 52/43/30 +f 37/35/31 36/38/31 49/50/31 50/47/31 +f 46/40/32 45/39/32 58/51/32 59/52/32 +f 44/42/33 43/41/33 56/53/33 57/54/33 +f 53/44/34 52/43/34 65/55/34 66/56/34 +f 42/46/35 41/45/35 54/57/35 55/58/35 +f 51/48/36 50/47/36 63/59/36 64/60/36 +f 49/50/37 48/49/37 61/61/37 62/62/37 +f 562/63/38 46/40/38 59/52/38 563/64/38 +f 45/39/39 44/42/39 57/54/39 58/51/39 +f 43/41/40 42/46/40 55/58/40 56/53/40 +f 52/43/41 51/48/41 64/60/41 65/55/41 +f 50/47/42 49/50/42 62/62/42 63/59/42 +f 59/52/43 58/51/43 71/65/43 72/66/43 +f 57/54/44 56/53/44 69/67/44 70/68/44 +f 66/56/45 65/55/45 79/69/45 80/70/45 +f 55/58/46 54/57/46 67/71/46 68/72/46 +f 64/60/47 63/59/47 77/73/47 78/74/47 +f 62/62/48 61/61/48 75/75/48 76/76/48 +f 58/51/49 57/54/49 70/68/49 71/65/49 +f 56/53/50 55/58/50 68/72/50 69/67/50 +f 65/55/51 64/60/51 78/74/51 79/69/51 +f 63/59/52 62/62/52 76/76/52 77/73/52 +f 543/77/53 60/77/53 74/78/53 544/78/53 +f 72/66/54 71/65/54 85/79/54 86/80/54 +f 70/68/55 69/67/55 83/81/55 84/82/55 +f 80/70/56 79/69/56 93/83/56 94/84/56 +f 68/72/57 67/71/57 81/85/57 82/86/57 +f 78/74/58 77/73/58 91/87/58 92/88/58 +f 76/76/59 75/75/59 89/89/59 90/90/59 +f 71/65/60 70/68/60 84/82/60 85/79/60 +f 69/67/61 68/72/61 82/86/61 83/81/61 +f 79/69/62 78/74/62 92/88/62 93/83/62 +f 77/73/63 76/76/63 90/90/63 91/87/63 +f 544/78/64 74/78/64 88/91/64 545/91/64 +f 86/80/65 85/79/65 99/92/65 100/93/65 +f 84/82/66 83/81/66 97/94/66 98/95/66 +f 94/84/67 93/83/67 106/96/67 107/97/67 +f 82/86/68 81/85/68 95/98/68 96/99/68 +f 92/88/69 91/87/69 104/100/69 105/101/69 +f 90/90/70 89/89/70 102/102/70 103/103/70 +f 85/79/71 84/82/71 98/95/71 99/92/71 +f 83/81/72 82/86/72 96/99/72 97/94/72 +f 93/83/73 92/88/73 105/101/73 106/96/73 +f 91/87/74 90/90/74 103/103/74 104/100/74 +f 545/91/75 88/91/75 101/104/75 546/104/75 +f 100/93/76 99/92/76 112/105/76 113/106/76 +f 98/95/77 97/94/77 110/107/77 111/108/77 +f 107/97/78 106/96/78 119/109/78 120/110/78 +f 96/99/79 95/98/79 108/111/79 109/112/79 +f 105/101/80 104/100/80 117/113/80 118/114/80 +f 103/103/81 102/102/81 115/115/81 116/116/81 +f 564/117/82 100/93/82 113/106/82 565/118/82 +f 99/92/83 98/95/83 111/108/83 112/105/83 +f 97/94/84 96/99/84 109/112/84 110/107/84 +f 106/96/85 105/101/85 118/114/85 119/109/85 +f 104/100/86 103/103/86 116/116/86 117/113/86 +f 546/104/53 101/104/53 114/119/53 547/119/53 +f 113/106/87 112/105/87 125/120/87 126/121/87 +f 111/108/88 110/107/88 123/122/88 124/123/88 +f 120/110/89 119/109/89 132/124/89 133/125/89 +f 109/112/90 108/111/90 121/126/90 122/127/90 +f 118/114/91 117/113/91 130/128/91 131/129/91 +f 116/116/92 115/115/92 128/130/92 129/131/92 +f 565/118/93 113/106/93 126/121/93 566/132/93 +f 112/105/94 111/108/94 124/123/94 125/120/94 +f 110/107/95 109/112/95 122/127/95 123/122/95 +f 119/109/96 118/114/96 131/129/96 132/124/96 +f 117/113/97 116/116/97 129/131/97 130/128/97 +f 547/119/53 114/119/53 127/133/53 548/133/53 +f 126/121/98 125/120/98 138/134/98 139/135/98 +f 124/123/99 123/122/99 136/136/99 137/137/99 +f 133/125/100 132/124/100 146/138/100 147/139/100 +f 122/127/101 121/126/101 134/140/101 135/141/101 +f 131/129/102 130/128/102 144/142/102 145/143/102 +f 129/131/103 128/130/103 142/144/103 143/145/103 +f 125/120/104 124/123/104 137/137/104 138/134/104 +f 123/122/105 122/127/105 135/141/105 136/136/105 +f 132/124/106 131/129/106 145/143/106 146/138/106 +f 130/128/107 129/131/107 143/145/107 144/142/107 +f 139/135/108 138/134/108 152/146/108 153/147/108 +f 137/137/109 136/136/109 150/148/109 151/149/109 +f 147/139/110 146/138/110 160/150/110 161/151/110 +f 135/141/111 134/140/111 148/152/111 149/153/111 +f 145/143/112 144/142/112 158/154/112 159/155/112 +f 143/145/113 142/144/113 156/156/113 157/157/113 +f 138/134/114 137/137/114 151/149/114 152/146/114 +f 136/136/115 135/141/115 149/153/115 150/148/115 +f 146/138/116 145/143/116 159/155/116 160/150/116 +f 144/142/117 143/145/117 157/157/117 158/154/117 +f 153/147/118 152/146/118 166/158/118 167/159/118 +f 151/149/119 150/148/119 164/160/119 165/161/119 +f 161/151/120 160/150/120 174/162/120 175/163/120 +f 149/153/121 148/152/121 162/164/121 163/165/121 +f 159/155/122 158/154/122 172/166/122 173/167/122 +f 157/157/123 156/156/123 170/168/123 171/169/123 +f 152/146/124 151/149/124 165/161/124 166/158/124 +f 150/148/125 149/153/125 163/165/125 164/160/125 +f 160/150/126 159/155/126 173/167/126 174/162/126 +f 158/154/127 157/157/127 171/169/127 172/166/127 +f 549/170/53 155/170/53 169/171/53 550/171/53 +f 167/159/128 166/158/128 180/172/128 181/173/128 +f 165/161/129 164/160/129 178/174/129 179/175/129 +f 175/163/130 174/162/130 187/176/130 188/177/130 +f 163/165/131 162/164/131 176/178/131 177/179/131 +f 173/167/132 172/166/132 185/180/132 186/181/132 +f 171/169/133 170/168/133 183/182/133 184/183/133 +f 166/158/134 165/161/134 179/175/134 180/172/134 +f 164/160/135 163/165/135 177/179/135 178/174/135 +f 174/162/136 173/167/136 186/181/136 187/176/136 +f 172/166/137 171/169/137 184/183/137 185/180/137 +f 550/171/53 169/171/53 182/184/53 551/184/53 +f 181/173/138 180/172/138 193/185/138 194/186/138 +f 179/175/139 178/174/139 191/187/139 192/188/139 +f 188/177/140 187/176/140 200/189/140 201/190/140 +f 177/179/141 176/178/141 189/191/141 190/192/141 +f 186/181/142 185/180/142 198/193/142 199/194/142 +f 184/183/143 183/182/143 196/195/143 197/196/143 +f 567/197/144 181/173/144 194/186/144 568/198/144 +f 180/172/145 179/175/145 192/188/145 193/185/145 +f 178/174/146 177/179/146 190/192/146 191/187/146 +f 187/176/147 186/181/147 199/194/147 200/189/147 +f 185/180/148 184/183/148 197/196/148 198/193/148 +f 551/184/53 182/184/53 195/199/53 552/199/53 +f 194/186/149 193/185/149 206/200/149 207/201/149 +f 192/188/150 191/187/150 204/202/150 205/203/150 +f 201/190/151 200/189/151 213/204/151 214/205/151 +f 190/192/152 189/191/152 202/206/152 203/207/152 +f 199/194/153 198/193/153 211/208/153 212/209/153 +f 197/196/154 196/195/154 209/210/154 210/211/154 +f 568/198/155 194/186/155 207/201/155 569/212/155 +f 193/185/156 192/188/156 205/203/156 206/200/156 +f 191/187/157 190/192/157 203/207/157 204/202/157 +f 200/189/158 199/194/158 212/209/158 213/204/158 +f 198/193/159 197/196/159 210/211/159 211/208/159 +f 207/201/160 206/200/160 219/213/160 220/214/160 +f 205/203/161 204/202/161 217/215/161 218/216/161 +f 214/205/162 213/204/162 227/217/162 228/218/162 +f 203/207/163 202/206/163 215/219/163 216/220/163 +f 212/209/164 211/208/164 225/221/164 226/222/164 +f 210/211/165 209/210/165 223/223/165 224/224/165 +f 206/200/166 205/203/166 218/216/166 219/213/166 +f 204/202/167 203/207/167 216/220/167 217/215/167 +f 213/204/168 212/209/168 226/222/168 227/217/168 +f 211/208/169 210/211/169 224/224/169 225/221/169 +f 220/214/170 219/213/170 233/225/170 234/226/170 +f 218/216/171 217/215/171 231/227/171 232/228/171 +f 228/218/172 227/217/172 240/229/172 241/230/172 +f 216/220/173 215/219/173 229/231/173 230/232/173 +f 226/222/174 225/221/174 238/233/174 239/234/174 +f 224/224/175 223/223/175 236/235/175 237/236/175 +f 219/213/176 218/216/176 232/228/176 233/225/176 +f 217/215/177 216/220/177 230/232/177 231/227/177 +f 227/217/178 226/222/178 239/234/178 240/229/178 +f 225/221/179 224/224/179 237/236/179 238/233/179 +f 234/226/180 233/225/180 246/237/180 247/238/180 +f 232/228/181 231/227/181 244/239/181 245/240/181 +f 241/230/182 240/229/182 253/241/182 254/242/182 +f 230/232/183 229/231/183 242/243/183 243/244/183 +f 239/234/184 238/233/184 251/245/184 252/246/184 +f 237/236/185 236/235/185 249/247/185 250/248/185 +f 570/249/186 234/226/186 247/238/186 571/250/186 +f 233/225/187 232/228/187 245/240/187 246/237/187 +f 231/227/188 230/232/188 243/244/188 244/239/188 +f 240/229/189 239/234/189 252/246/189 253/241/189 +f 238/233/190 237/236/190 250/248/190 251/245/190 +f 247/238/191 246/237/191 259/251/191 260/252/191 +f 245/240/192 244/239/192 257/253/192 258/254/192 +f 254/242/193 253/241/193 267/255/193 268/256/193 +f 243/244/194 242/243/194 255/257/194 256/258/194 +f 252/246/195 251/245/195 265/259/195 266/260/195 +f 250/248/196 249/247/196 263/261/196 264/262/196 +f 246/237/197 245/240/197 258/254/197 259/251/197 +f 244/239/198 243/244/198 256/258/198 257/253/198 +f 253/241/199 252/246/199 266/260/199 267/255/199 +f 251/245/200 250/248/200 264/262/200 265/259/200 +f 260/252/201 259/251/201 273/263/201 274/264/201 +f 258/254/202 257/253/202 271/265/202 272/266/202 +f 268/256/203 267/255/203 281/267/203 282/268/203 +f 256/258/204 255/257/204 269/269/204 270/270/204 +f 266/260/205 265/259/205 279/271/205 280/272/205 +f 264/262/206 263/261/206 277/273/206 278/274/206 +f 259/251/207 258/254/207 272/266/207 273/263/207 +f 257/253/208 256/258/208 270/270/208 271/265/208 +f 267/255/209 266/260/209 280/272/209 281/267/209 +f 265/259/210 264/262/210 278/274/210 279/271/210 +f 274/264/211 273/263/211 287/275/211 288/276/211 +f 272/266/212 271/265/212 285/277/212 286/278/212 +f 282/268/213 281/267/213 295/279/213 296/280/213 +f 270/270/214 269/269/214 283/281/214 284/282/214 +f 280/272/215 279/271/215 293/283/215 294/284/215 +f 278/274/216 277/273/216 291/285/216 292/286/216 +f 273/263/217 272/266/217 286/278/217 287/275/217 +f 271/265/218 270/270/218 284/282/218 285/277/218 +f 281/267/219 280/272/219 294/284/219 295/279/219 +f 279/271/220 278/274/220 292/286/220 293/283/220 +f 288/276/221 287/275/221 302/287/221 303/288/221 +f 286/278/222 285/277/222 300/289/222 301/290/222 +f 296/280/223 295/279/223 309/291/223 310/292/223 +f 284/282/224 283/281/224 298/293/224 299/294/224 +f 294/284/225 293/283/225 307/295/225 308/296/225 +f 292/286/226 291/285/226 305/297/226 306/298/226 +f 287/275/227 286/278/227 301/290/227 302/287/227 +f 285/277/228 284/282/228 299/294/228 300/289/228 +f 295/279/229 294/284/229 308/296/229 309/291/229 +f 293/283/230 292/286/230 306/298/230 307/295/230 +f 303/288/231 302/287/231 315/299/231 316/300/231 +f 301/290/232 300/289/232 313/301/232 314/302/232 +f 310/292/233 309/291/233 322/303/233 323/304/233 +f 299/294/234 298/293/234 311/305/234 312/306/234 +f 308/296/235 307/295/235 320/307/235 321/308/235 +f 306/298/236 305/297/236 318/309/236 319/310/236 +f 572/311/237 303/288/237 316/300/237 573/312/237 +f 302/287/238 301/290/238 314/302/238 315/299/238 +f 300/289/239 299/294/239 312/306/239 313/301/239 +f 309/291/240 308/296/240 321/308/240 322/303/240 +f 307/295/241 306/298/241 319/310/241 320/307/241 +f 316/300/242 315/299/242 328/313/242 329/314/242 +f 314/302/243 313/301/243 326/315/243 327/316/243 +f 323/304/244 322/303/244 335/317/244 336/318/244 +f 312/306/245 311/305/245 324/319/245 325/320/245 +f 321/308/246 320/307/246 333/321/246 334/322/246 +f 319/310/247 318/309/247 331/323/247 332/324/247 +f 573/312/248 316/300/248 329/314/248 574/325/248 +f 315/299/249 314/302/249 327/316/249 328/313/249 +f 313/301/250 312/306/250 325/320/250 326/315/250 +f 322/303/251 321/308/251 334/322/251 335/317/251 +f 320/307/252 319/310/252 332/324/252 333/321/252 +f 329/314/253 328/313/253 341/326/253 342/327/253 +f 327/316/254 326/315/254 339/328/254 340/329/254 +f 336/318/255 335/317/255 348/330/255 349/331/255 +f 325/320/256 324/319/256 337/332/256 338/333/256 +f 334/322/257 333/321/257 346/334/257 347/335/257 +f 332/324/258 331/323/258 344/336/258 345/337/258 +f 574/325/259 329/314/259 342/327/259 575/338/259 +f 328/313/260 327/316/260 340/329/260 341/326/260 +f 326/315/261 325/320/261 338/333/261 339/328/261 +f 335/317/262 334/322/262 347/335/262 348/330/262 +f 333/321/263 332/324/263 345/337/263 346/334/263 +f 342/327/264 341/326/264 354/339/264 355/340/264 +f 340/329/265 339/328/265 352/341/265 353/342/265 +f 349/331/266 348/330/266 361/343/266 362/344/266 +f 338/333/267 337/332/267 350/345/267 351/346/267 +f 347/335/268 346/334/268 359/347/268 360/348/268 +f 345/337/269 344/336/269 357/349/269 358/350/269 +f 575/338/270 342/327/270 355/340/270 576/351/270 +f 341/326/271 340/329/271 353/342/271 354/339/271 +f 339/328/272 338/333/272 351/346/272 352/341/272 +f 348/330/273 347/335/273 360/348/273 361/343/273 +f 346/334/274 345/337/274 358/350/274 359/347/274 +f 355/340/275 354/339/275 367/352/275 368/353/275 +f 353/342/276 352/341/276 365/354/276 366/355/276 +f 362/344/277 361/343/277 375/356/277 376/357/277 +f 351/346/278 350/345/278 363/358/278 364/359/278 +f 360/348/279 359/347/279 373/360/279 374/361/279 +f 358/350/280 357/349/280 371/362/280 372/363/280 +f 354/339/281 353/342/281 366/355/281 367/352/281 +f 352/341/282 351/346/282 364/359/282 365/354/282 +f 361/343/283 360/348/283 374/361/283 375/356/283 +f 359/347/284 358/350/284 372/363/284 373/360/284 +f 555/364/53 356/364/53 370/365/53 556/365/53 +f 368/353/285 367/352/285 381/366/285 382/367/285 +f 366/355/286 365/354/286 379/368/286 380/369/286 +f 376/357/287 375/356/287 388/370/287 389/371/287 +f 364/359/288 363/358/288 377/372/288 378/373/288 +f 374/361/289 373/360/289 386/374/289 387/375/289 +f 372/363/290 371/362/290 384/376/290 385/377/290 +f 367/352/291 366/355/291 380/369/291 381/366/291 +f 365/354/292 364/359/292 378/373/292 379/368/292 +f 375/356/293 374/361/293 387/375/293 388/370/293 +f 373/360/294 372/363/294 385/377/294 386/374/294 +f 556/365/53 370/365/53 383/378/53 557/378/53 +f 382/367/295 381/366/295 394/379/295 395/380/295 +f 380/369/296 379/368/296 392/381/296 393/382/296 +f 389/371/297 388/370/297 402/383/297 403/384/297 +f 378/373/298 377/372/298 390/385/298 391/386/298 +f 387/375/299 386/374/299 400/387/299 401/388/299 +f 385/377/300 384/376/300 398/389/300 399/390/300 +f 381/366/301 380/369/301 393/382/301 394/379/301 +f 379/368/302 378/373/302 391/386/302 392/381/302 +f 388/370/303 387/375/303 401/388/303 402/383/303 +f 386/374/304 385/377/304 399/390/304 400/387/304 +f 557/378/53 383/378/53 397/391/53 558/391/53 +f 395/380/305 394/379/305 409/392/305 410/393/305 +f 393/382/306 392/381/306 407/394/306 408/395/306 +f 403/384/307 402/383/307 416/396/307 417/397/307 +f 391/386/308 390/385/308 405/398/308 406/399/308 +f 401/388/309 400/387/309 414/400/309 415/401/309 +f 399/390/310 398/389/310 412/402/310 413/403/310 +f 394/379/311 393/382/311 408/395/311 409/392/311 +f 392/381/312 391/386/312 406/399/312 407/394/312 +f 402/383/313 401/388/313 415/401/313 416/396/313 +f 400/387/314 399/390/314 413/403/314 414/400/314 +f 410/393/315 409/392/315 422/404/315 423/405/315 +f 408/395/316 407/394/316 420/406/316 421/407/316 +f 417/397/317 416/396/317 430/408/317 431/409/317 +f 406/399/318 405/398/318 418/410/318 419/411/318 +f 415/401/319 414/400/319 428/412/319 429/413/319 +f 413/403/320 412/402/320 426/414/320 427/415/320 +f 409/392/321 408/395/321 421/407/321 422/404/321 +f 407/394/322 406/399/322 419/411/322 420/406/322 +f 416/396/323 415/401/323 429/413/323 430/408/323 +f 414/400/324 413/403/324 427/415/324 428/412/324 +f 297/416/325 13/23/325 26/24/325 +f 1/25/326 404/417/326 14/26/326 +f 297/416/327 26/24/327 40/32/327 +f 14/26/328 404/417/328 27/33/328 +f 297/416/329 40/32/329 53/44/329 +f 27/33/330 404/417/330 41/45/330 +f 297/416/331 53/44/331 66/56/331 +f 41/45/332 404/417/332 54/57/332 +f 297/416/333 66/56/333 80/70/333 +f 54/57/334 404/417/334 67/71/334 +f 297/416/335 80/70/335 94/84/335 +f 67/71/336 404/417/336 81/85/336 +f 297/416/337 94/84/337 107/97/337 +f 81/85/338 404/417/338 95/98/338 +f 297/416/339 107/97/339 120/110/339 +f 95/98/340 404/417/340 108/111/340 +f 297/416/341 120/110/341 133/125/341 +f 108/111/342 404/417/342 121/126/342 +f 297/416/343 133/125/343 147/139/343 +f 121/126/344 404/417/344 134/140/344 +f 297/416/345 147/139/345 161/151/345 +f 134/140/346 404/417/346 148/152/346 +f 297/416/347 161/151/347 175/163/347 +f 148/152/348 404/417/348 162/164/348 +f 297/416/349 175/163/349 188/177/349 +f 162/164/350 404/417/350 176/178/350 +f 297/416/351 188/177/351 201/190/351 +f 176/178/352 404/417/352 189/191/352 +f 297/416/353 201/190/353 214/205/353 +f 189/191/354 404/417/354 202/206/354 +f 297/416/355 214/205/355 228/218/355 +f 202/206/356 404/417/356 215/219/356 +f 297/416/357 228/218/357 241/230/357 +f 215/219/358 404/417/358 229/231/358 +f 297/416/359 241/230/359 254/242/359 +f 229/231/360 404/417/360 242/243/360 +f 297/416/361 254/242/361 268/256/361 +f 242/243/362 404/417/362 255/257/362 +f 297/416/363 268/256/363 282/268/363 +f 255/257/364 404/417/364 269/269/364 +f 297/416/365 282/268/365 296/280/365 +f 269/269/366 404/417/366 283/281/366 +f 297/416/367 296/280/367 310/292/367 +f 283/281/368 404/417/368 298/293/368 +f 297/416/369 310/292/369 323/304/369 +f 298/293/370 404/417/370 311/305/370 +f 297/416/371 323/304/371 336/318/371 +f 311/305/372 404/417/372 324/319/372 +f 297/416/373 336/318/373 349/331/373 +f 324/319/374 404/417/374 337/332/374 +f 297/416/375 349/331/375 362/344/375 +f 337/332/376 404/417/376 350/345/376 +f 297/416/377 362/344/377 376/357/377 +f 350/345/378 404/417/378 363/358/378 +f 297/416/379 376/357/379 389/371/379 +f 363/358/380 404/417/380 377/372/380 +f 297/416/381 389/371/381 403/384/381 +f 377/372/382 404/417/382 390/385/382 +f 297/416/383 403/384/383 417/397/383 +f 390/385/384 404/417/384 405/398/384 +f 297/416/385 417/397/385 431/409/385 +f 405/398/386 404/417/386 418/410/386 +f 423/405/387 422/404/387 5/9/387 6/6/387 +f 421/407/388 420/406/388 3/13/388 4/10/388 +f 431/409/389 430/408/389 12/17/389 13/23/389 +f 419/411/390 418/410/390 1/25/390 2/14/390 +f 429/413/391 428/412/391 10/21/391 11/18/391 +f 427/415/392 426/414/392 8/2/392 9/1/392 +f 422/404/393 421/407/393 4/10/393 5/9/393 +f 297/416/394 431/409/394 13/23/394 +f 420/406/395 419/411/395 2/14/395 3/13/395 +f 430/408/396 429/413/396 11/18/396 12/17/396 +f 418/410/397 404/417/397 1/25/397 +f 428/412/398 427/415/398 9/1/398 10/21/398 +f 290/418/53 276/419/53 452/419/53 453/418/53 +f 34/420/53 20/421/53 433/421/53 434/420/53 +f 182/184/53 169/171/53 444/171/53 445/184/53 +f 356/364/53 343/422/53 457/422/53 458/364/53 +f 248/423/53 235/424/53 449/424/53 450/423/53 +f 101/104/53 88/91/53 438/91/53 439/104/53 +f 7/425/53 425/426/53 463/426/53 432/425/53 +f 169/171/53 155/170/53 443/170/53 444/171/53 +f 343/422/53 330/427/53 456/427/53 457/422/53 +f 235/424/53 222/428/53 448/428/53 449/424/53 +f 88/91/53 74/78/53 437/78/53 438/91/53 +f 155/170/53 141/429/53 442/429/53 443/170/53 +f 330/427/53 317/430/53 455/430/53 456/427/53 +f 74/78/53 60/77/53 436/77/53 437/78/53 +f 222/428/53 208/431/53 447/431/53 448/428/53 +f 397/391/53 383/378/53 460/378/53 461/391/53 +f 141/429/53 127/133/53 441/133/53 442/429/53 +f 425/426/53 411/432/53 462/432/53 463/426/53 +f 317/430/53 304/433/53 454/433/53 455/430/53 +f 20/421/53 7/425/53 432/425/53 433/421/53 +f 60/77/53 47/434/53 435/434/53 436/77/53 +f 208/431/53 195/435/53 446/435/53 447/431/53 +f 383/378/53 370/365/53 459/365/53 460/378/53 +f 276/419/53 262/436/53 451/436/53 452/419/53 +f 127/133/53 114/119/53 440/119/53 441/133/53 +f 411/432/53 397/391/53 461/391/53 462/432/53 +f 304/433/53 290/418/53 453/418/53 454/433/53 +f 47/434/53 34/420/53 434/420/53 435/434/53 +f 195/199/53 182/184/53 445/184/53 446/199/53 +f 370/365/53 356/364/53 458/364/53 459/365/53 +f 262/436/53 248/423/53 450/423/53 451/436/53 +f 114/119/53 101/104/53 439/104/53 440/119/53 +f 457/422/53 456/427/53 488/427/53 489/422/53 +f 435/434/53 434/420/53 466/420/53 467/434/53 +f 446/199/53 445/184/53 477/184/53 478/199/53 +f 455/430/53 454/433/53 486/433/53 487/430/53 +f 433/421/53 432/425/53 464/425/53 465/421/53 +f 444/171/53 443/170/53 475/170/53 476/171/53 +f 432/425/53 463/426/53 495/426/53 464/425/53 +f 453/418/53 452/419/53 484/419/53 485/418/53 +f 442/429/53 441/133/53 473/133/53 474/429/53 +f 462/432/53 461/391/53 493/391/53 494/432/53 +f 451/436/53 450/423/53 482/423/53 483/436/53 +f 440/119/53 439/104/53 471/104/53 472/119/53 +f 460/378/53 459/365/53 491/365/53 492/378/53 +f 449/424/53 448/428/53 480/428/53 481/424/53 +f 438/91/53 437/78/53 469/78/53 470/91/53 +f 458/364/53 457/422/53 489/422/53 490/364/53 +f 436/77/53 435/434/53 467/434/53 468/77/53 +f 447/431/53 446/435/53 478/435/53 479/431/53 +f 456/427/53 455/430/53 487/430/53 488/427/53 +f 434/420/53 433/421/53 465/421/53 466/420/53 +f 445/184/53 444/171/53 476/171/53 477/184/53 +f 454/433/53 453/418/53 485/418/53 486/433/53 +f 443/170/53 442/429/53 474/429/53 475/170/53 +f 463/426/53 462/432/53 494/432/53 495/426/53 +f 452/419/53 451/436/53 483/436/53 484/419/53 +f 441/133/53 440/119/53 472/119/53 473/133/53 +f 461/391/53 460/378/53 492/378/53 493/391/53 +f 450/423/53 449/424/53 481/424/53 482/423/53 +f 439/104/53 438/91/53 470/91/53 471/104/53 +f 459/365/53 458/364/53 490/364/53 491/365/53 +f 437/78/53 436/77/53 468/77/53 469/78/53 +f 448/428/53 447/431/53 479/431/53 480/428/53 +f 511/431/53 512/428/53 533/428/53 532/431/53 +f 520/427/53 521/422/53 540/422/53 539/427/53 +f 518/433/53 519/430/53 538/430/53 537/433/53 +f 496/425/53 497/421/53 529/421/53 528/425/53 +f 516/419/53 517/418/53 536/418/53 535/419/53 +f 519/430/53 520/427/53 539/427/53 538/430/53 +f 517/418/53 518/433/53 537/433/53 536/418/53 +f 61/61/399 543/437/399 544/438/399 75/75/399 +f 75/75/400 544/438/400 545/439/400 89/89/400 +f 89/89/401 545/439/401 546/440/401 102/102/401 +f 102/102/402 546/440/402 547/441/402 115/115/402 +f 115/115/403 547/441/403 548/442/403 128/130/403 +f 156/156/404 549/443/404 550/444/404 170/168/404 +f 170/168/405 550/444/405 551/445/405 183/182/405 +f 183/182/406 551/445/406 552/446/406 196/195/406 +f 357/349/407 555/447/407 556/448/407 371/362/407 +f 371/362/408 556/448/408 557/449/408 384/376/408 +f 384/376/409 557/449/409 558/450/409 398/389/409 +f 528/425/53 7/425/53 20/421/53 529/421/53 +f 561/8/410 19/7/410 32/28/410 33/451/410 +f 529/421/53 20/421/53 34/420/53 542/420/53 +f 33/451/411 32/28/411 46/40/411 562/63/411 +f 542/420/53 34/420/53 47/434/53 530/434/53 +f 530/434/53 47/434/53 60/77/53 543/77/53 +f 563/64/412 59/52/412 72/66/412 73/452/412 +f 73/452/413 72/66/413 86/80/413 87/453/413 +f 87/453/414 86/80/414 100/93/414 564/117/414 +f 566/132/415 126/121/415 139/135/415 140/454/415 +f 548/133/53 127/133/53 141/429/53 531/429/53 +f 140/454/416 139/135/416 153/147/416 154/455/416 +f 531/429/53 141/429/53 155/170/53 549/170/53 +f 154/455/417 153/147/417 167/159/417 168/456/417 +f 168/456/418 167/159/418 181/173/418 567/197/418 +f 552/435/53 195/435/53 208/431/53 532/431/53 +f 569/212/419 207/201/419 220/214/419 221/457/419 +f 532/431/53 208/431/53 222/428/53 533/428/53 +f 221/457/420 220/214/420 234/226/420 570/249/420 +f 533/428/53 222/428/53 235/424/53 553/424/53 +f 553/424/53 235/424/53 248/423/53 534/423/53 +f 571/250/421 247/238/421 260/252/421 261/458/421 +f 534/423/53 248/423/53 262/436/53 554/436/53 +f 261/458/422 260/252/422 274/264/422 275/459/422 +f 554/436/53 262/436/53 276/419/53 535/419/53 +f 275/459/423 274/264/423 288/276/423 289/460/423 +f 535/419/53 276/419/53 290/418/53 536/418/53 +f 289/460/424 288/276/424 303/288/424 572/311/424 +f 536/418/53 290/418/53 304/433/53 537/433/53 +f 537/433/53 304/433/53 317/430/53 538/430/53 +f 538/430/53 317/430/53 330/427/53 539/427/53 +f 539/427/53 330/427/53 343/422/53 540/422/53 +f 540/422/53 343/422/53 356/364/53 555/364/53 +f 576/351/425 355/340/425 368/353/425 369/461/425 +f 369/461/426 368/353/426 382/367/426 577/462/426 +f 577/462/427 382/367/427 395/380/427 396/463/427 +f 396/463/428 395/380/428 410/393/428 578/464/428 +f 558/391/53 397/391/53 411/432/53 541/432/53 +f 578/464/429 410/393/429 423/405/429 424/465/429 +f 541/432/53 411/432/53 425/426/53 559/426/53 +f 424/465/430 423/405/430 6/6/430 560/5/430 +f 559/426/53 425/426/53 7/425/53 528/425/53 +f 524/378/53 525/391/53 558/391/53 557/378/53 +f 513/424/53 514/423/53 534/423/53 553/424/53 +f 502/91/75 503/104/75 546/104/75 545/91/75 +f 522/364/53 523/365/53 556/365/53 555/364/53 +f 500/77/53 501/78/53 544/78/53 543/77/53 +f 498/420/53 499/434/53 530/434/53 542/420/53 +f 509/184/53 510/199/53 552/199/53 551/184/53 +f 507/170/53 508/171/53 550/171/53 549/170/53 +f 527/426/53 496/425/53 528/425/53 559/426/53 +f 505/133/53 506/429/53 531/429/53 548/133/53 +f 525/391/53 526/432/53 541/432/53 558/391/53 +f 514/423/53 515/436/53 554/436/53 534/423/53 +f 503/104/53 504/119/53 547/119/53 546/104/53 +f 523/365/53 524/378/53 557/378/53 556/365/53 +f 512/428/53 513/424/53 553/424/53 533/428/53 +f 501/78/431 502/91/431 545/91/431 544/78/431 +f 521/422/53 522/364/53 555/364/53 540/422/53 +f 499/434/53 500/77/53 543/77/53 530/434/53 +f 510/435/53 511/431/53 532/431/53 552/435/53 +f 497/421/53 498/420/53 542/420/53 529/421/53 +f 508/171/53 509/184/53 551/184/53 550/171/53 +f 506/429/53 507/170/53 549/170/53 531/429/53 +f 526/432/53 527/426/53 559/426/53 541/432/53 +f 515/436/53 516/419/53 535/419/53 554/436/53 +f 504/119/53 505/133/53 548/133/53 547/119/53 +f 529/466/432 528/467/432 559/468/432 541/469/432 558/470/432 557/471/432 556/472/432 555/473/432 540/474/432 539/475/432 538/476/432 537/477/432 536/478/432 535/479/432 554/480/432 534/481/432 553/482/432 533/483/432 532/484/432 552/485/432 551/486/432 550/487/432 549/488/432 531/489/432 548/490/432 547/491/432 546/492/432 545/493/432 544/494/432 543/495/432 530/496/432 542/497/432 +f 561/498/433 33/499/433 562/500/433 563/501/433 73/502/433 87/503/433 564/504/433 565/505/433 566/506/433 140/507/433 154/508/433 168/509/433 567/510/433 568/511/433 569/512/433 221/513/433 570/514/433 571/515/433 261/516/433 275/517/433 289/518/433 572/519/433 573/520/433 574/521/433 575/522/433 576/523/433 369/524/433 577/525/433 396/526/433 578/527/433 424/528/433 560/529/433 +f 8/2/434 528/530/434 529/531/434 21/3/434 +f 21/3/435 529/531/435 542/532/435 35/37/435 +f 35/37/436 542/532/436 530/533/436 48/49/436 +f 48/49/437 530/533/437 543/437/437 61/61/437 +f 128/130/438 548/442/438 531/534/438 142/144/438 +f 142/144/439 531/534/439 549/443/439 156/156/439 +f 196/195/440 552/446/440 532/535/440 209/210/440 +f 209/210/441 532/535/441 533/536/441 223/223/441 +f 223/223/442 533/536/442 553/537/442 236/235/442 +f 236/235/443 553/537/443 534/538/443 249/247/443 +f 249/247/444 534/538/444 554/539/444 263/261/444 +f 263/261/445 554/539/445 535/540/445 277/273/445 +f 277/273/446 535/540/446 536/541/446 291/285/446 +f 291/285/447 536/541/447 537/542/447 305/297/447 +f 305/297/448 537/542/448 538/543/448 318/309/448 +f 318/309/449 538/543/449 539/544/449 331/323/449 +f 331/323/450 539/544/450 540/545/450 344/336/450 +f 344/336/451 540/545/451 555/447/451 357/349/451 +f 398/389/452 558/450/452 541/546/452 412/402/452 +f 412/402/453 541/546/453 559/547/453 426/414/453 +f 426/414/454 559/547/454 528/530/454 8/2/454 diff --git a/Geometry/Quad.ab b/Levels/Geometry/Quad.ab similarity index 100% rename from Geometry/Quad.ab rename to Levels/Geometry/Quad.ab diff --git a/Levels/Geometry/Sphere.obj b/Levels/Geometry/Sphere.obj new file mode 100644 index 0000000..162d5b7 --- /dev/null +++ b/Levels/Geometry/Sphere.obj @@ -0,0 +1,2069 @@ +# Blender v2.72 (sub 0) OBJ File: '' +# www.blender.org +o Sphere +v -0.195090 0.980785 0.000000 +v -0.382683 0.923880 0.000000 +v -0.555570 0.831470 0.000000 +v -0.707107 0.707107 0.000000 +v -0.831470 0.555570 0.000000 +v -0.923880 0.382683 0.000000 +v -0.980785 0.195090 0.000000 +v -1.000000 0.000000 0.000000 +v -0.980785 -0.195090 0.000000 +v -0.923880 -0.382683 0.000000 +v -0.831470 -0.555570 0.000000 +v -0.707107 -0.707107 0.000000 +v -0.555570 -0.831470 0.000000 +v -0.382683 -0.923880 0.000000 +v -0.195090 -0.980785 0.000000 +v 0.000000 -1.000000 0.000000 +v -0.191342 0.980785 -0.038060 +v -0.375330 0.923880 -0.074658 +v -0.544895 0.831470 -0.108386 +v -0.693520 0.707107 -0.137950 +v -0.815493 0.555570 -0.162212 +v -0.906127 0.382683 -0.180240 +v -0.961940 0.195090 -0.191342 +v -0.980785 0.000000 -0.195090 +v -0.961940 -0.195090 -0.191342 +v -0.906127 -0.382683 -0.180240 +v -0.815493 -0.555570 -0.162212 +v -0.693520 -0.707107 -0.137950 +v -0.544895 -0.831470 -0.108386 +v -0.375330 -0.923880 -0.074658 +v -0.191341 -0.980785 -0.038060 +v -0.180240 0.980785 -0.074658 +v -0.353553 0.923880 -0.146447 +v -0.513280 0.831470 -0.212608 +v -0.653281 0.707107 -0.270598 +v -0.768178 0.555570 -0.318190 +v -0.853553 0.382683 -0.353553 +v -0.906127 0.195090 -0.375330 +v -0.923879 0.000000 -0.382684 +v -0.906127 -0.195090 -0.375330 +v -0.853553 -0.382683 -0.353554 +v -0.768178 -0.555570 -0.318190 +v -0.653281 -0.707107 -0.270598 +v -0.513280 -0.831470 -0.212608 +v -0.353553 -0.923880 -0.146447 +v -0.180240 -0.980785 -0.074658 +v -0.162212 0.980785 -0.108387 +v -0.318190 0.923880 -0.212608 +v -0.461940 0.831470 -0.308658 +v -0.587938 0.707107 -0.392848 +v -0.691342 0.555570 -0.461940 +v -0.768178 0.382683 -0.513280 +v -0.815493 0.195090 -0.544895 +v -0.831469 0.000000 -0.555570 +v -0.815493 -0.195090 -0.544895 +v -0.768178 -0.382683 -0.513280 +v -0.691342 -0.555570 -0.461940 +v -0.587938 -0.707107 -0.392848 +v -0.461940 -0.831470 -0.308658 +v -0.318189 -0.923880 -0.212608 +v -0.162211 -0.980785 -0.108386 +v -0.137950 0.980785 -0.137950 +v -0.270598 0.923880 -0.270598 +v -0.392847 0.831470 -0.392848 +v -0.500000 0.707107 -0.500000 +v -0.587938 0.555570 -0.587938 +v -0.653281 0.382683 -0.653282 +v -0.693520 0.195090 -0.693520 +v -0.707107 0.000000 -0.707107 +v -0.693520 -0.195090 -0.693520 +v -0.653281 -0.382683 -0.653282 +v -0.587938 -0.555570 -0.587938 +v -0.500000 -0.707107 -0.500000 +v -0.392847 -0.831470 -0.392848 +v -0.270598 -0.923880 -0.270598 +v -0.137949 -0.980785 -0.137950 +v -0.108386 0.980785 -0.162212 +v -0.212607 0.923880 -0.318190 +v -0.308658 0.831470 -0.461940 +v -0.392847 0.707107 -0.587938 +v -0.461940 0.555570 -0.691342 +v -0.513280 0.382683 -0.768178 +v -0.544895 0.195090 -0.815493 +v -0.555570 0.000000 -0.831470 +v -0.544895 -0.195090 -0.815493 +v -0.513280 -0.382683 -0.768178 +v -0.461940 -0.555570 -0.691342 +v -0.392847 -0.707107 -0.587938 +v -0.308658 -0.831470 -0.461940 +v -0.212607 -0.923880 -0.318190 +v -0.108386 -0.980785 -0.162212 +v -0.074658 0.980785 -0.180240 +v -0.146446 0.923880 -0.353554 +v -0.212607 0.831470 -0.513280 +v -0.270598 0.707107 -0.653282 +v -0.318189 0.555570 -0.768178 +v -0.353553 0.382683 -0.853554 +v -0.375330 0.195090 -0.906128 +v -0.382683 0.000000 -0.923880 +v -0.375330 -0.195090 -0.906128 +v -0.353553 -0.382683 -0.853554 +v -0.318189 -0.555570 -0.768178 +v -0.270598 -0.707107 -0.653282 +v -0.212607 -0.831470 -0.513280 +v -0.146446 -0.923880 -0.353554 +v -0.074658 -0.980785 -0.180240 +v -0.038060 0.980785 -0.191342 +v -0.074658 0.923880 -0.375331 +v -0.108386 0.831470 -0.544895 +v -0.137949 0.707107 -0.693520 +v -0.162211 0.555570 -0.815493 +v -0.180240 0.382683 -0.906128 +v -0.191341 0.195090 -0.961940 +v -0.195090 0.000000 -0.980785 +v -0.191341 -0.195090 -0.961940 +v -0.180240 -0.382683 -0.906128 +v -0.162211 -0.555570 -0.815493 +v -0.137949 -0.707107 -0.693520 +v -0.108386 -0.831470 -0.544895 +v -0.074658 -0.923880 -0.375330 +v -0.038060 -0.980785 -0.191342 +v 0.000000 0.980785 -0.195091 +v 0.000000 0.923880 -0.382684 +v 0.000000 0.831470 -0.555570 +v 0.000000 0.707107 -0.707107 +v 0.000000 0.555570 -0.831470 +v 0.000000 0.382683 -0.923880 +v 0.000000 0.195090 -0.980785 +v 0.000000 0.000000 -1.000000 +v 0.000000 -0.195090 -0.980785 +v 0.000000 -0.382683 -0.923880 +v 0.000000 -0.555570 -0.831470 +v 0.000000 -0.707107 -0.707107 +v 0.000000 -0.831470 -0.555570 +v 0.000000 -0.923880 -0.382684 +v 0.000000 -0.980785 -0.195090 +v 0.038061 0.980785 -0.191342 +v 0.074658 0.923880 -0.375331 +v 0.108387 0.831470 -0.544895 +v 0.137950 0.707107 -0.693520 +v 0.162212 0.555570 -0.815493 +v 0.180240 0.382683 -0.906128 +v 0.191342 0.195090 -0.961940 +v 0.195091 0.000000 -0.980785 +v 0.191342 -0.195090 -0.961940 +v 0.180240 -0.382683 -0.906128 +v 0.162212 -0.555570 -0.815493 +v 0.137950 -0.707107 -0.693520 +v 0.108387 -0.831470 -0.544895 +v 0.074658 -0.923880 -0.375330 +v 0.038061 -0.980785 -0.191342 +v 0.074658 0.980785 -0.180240 +v 0.146447 0.923880 -0.353554 +v 0.212608 0.831470 -0.513280 +v 0.270598 0.707107 -0.653282 +v 0.318190 0.555570 -0.768178 +v 0.353554 0.382683 -0.853554 +v 0.375331 0.195090 -0.906127 +v 0.382684 0.000000 -0.923880 +v 0.375331 -0.195090 -0.906127 +v 0.353554 -0.382683 -0.853554 +v 0.318190 -0.555570 -0.768178 +v 0.270598 -0.707107 -0.653282 +v 0.212608 -0.831470 -0.513280 +v 0.146447 -0.923880 -0.353553 +v 0.074658 -0.980785 -0.180240 +v 0.108387 0.980785 -0.162212 +v 0.212608 0.923880 -0.318190 +v 0.308659 0.831470 -0.461940 +v 0.392848 0.707107 -0.587938 +v 0.461940 0.555570 -0.691342 +v 0.513280 0.382683 -0.768178 +v 0.544895 0.195090 -0.815493 +v 0.555571 0.000000 -0.831470 +v 0.544895 -0.195090 -0.815493 +v 0.513280 -0.382683 -0.768178 +v 0.461940 -0.555570 -0.691342 +v 0.392848 -0.707107 -0.587938 +v 0.308659 -0.831470 -0.461940 +v 0.212608 -0.923880 -0.318190 +v 0.108387 -0.980785 -0.162212 +v 0.137950 0.980785 -0.137950 +v 0.270599 0.923880 -0.270598 +v 0.392848 0.831470 -0.392848 +v 0.500000 0.707107 -0.500000 +v 0.587938 0.555570 -0.587938 +v 0.653282 0.382683 -0.653282 +v 0.693520 0.195090 -0.693520 +v 0.707107 0.000000 -0.707107 +v 0.693520 -0.195090 -0.693520 +v 0.653282 -0.382683 -0.653282 +v 0.587938 -0.555570 -0.587938 +v 0.500000 -0.707107 -0.500000 +v 0.392848 -0.831470 -0.392848 +v 0.270598 -0.923880 -0.270598 +v 0.137950 -0.980785 -0.137950 +v 0.162212 0.980785 -0.108386 +v 0.318190 0.923880 -0.212608 +v 0.461940 0.831470 -0.308658 +v 0.587938 0.707107 -0.392848 +v 0.691342 0.555570 -0.461940 +v 0.768178 0.382683 -0.513280 +v 0.815493 0.195090 -0.544895 +v 0.831470 0.000000 -0.555570 +v 0.815493 -0.195090 -0.544895 +v 0.768178 -0.382683 -0.513280 +v 0.691342 -0.555570 -0.461940 +v 0.587938 -0.707107 -0.392848 +v 0.461940 -0.831470 -0.308658 +v 0.318190 -0.923880 -0.212608 +v 0.162212 -0.980785 -0.108386 +v 0.180240 0.980785 -0.074658 +v 0.353554 0.923880 -0.146447 +v 0.513280 0.831470 -0.212608 +v 0.653282 0.707107 -0.270598 +v 0.768178 0.555570 -0.318190 +v 0.853554 0.382683 -0.353553 +v 0.906128 0.195090 -0.375330 +v 0.923880 0.000000 -0.382683 +v 0.906128 -0.195090 -0.375330 +v 0.853554 -0.382683 -0.353553 +v 0.768178 -0.555570 -0.318190 +v 0.653282 -0.707107 -0.270598 +v 0.513280 -0.831470 -0.212608 +v 0.353554 -0.923880 -0.146447 +v 0.180240 -0.980785 -0.074658 +v 0.191342 0.980785 -0.038060 +v 0.375331 0.923880 -0.074658 +v 0.544896 0.831470 -0.108386 +v 0.693520 0.707107 -0.137950 +v 0.815493 0.555570 -0.162212 +v 0.906128 0.382683 -0.180240 +v 0.961940 0.195090 -0.191342 +v 0.980786 0.000000 -0.195090 +v 0.961940 -0.195090 -0.191342 +v 0.906128 -0.382683 -0.180240 +v 0.815493 -0.555570 -0.162212 +v 0.693520 -0.707107 -0.137950 +v 0.544895 -0.831470 -0.108386 +v 0.375331 -0.923880 -0.074658 +v 0.191342 -0.980785 -0.038060 +v 0.195091 0.980785 0.000000 +v 0.382684 0.923880 -0.000000 +v 0.555571 0.831470 -0.000000 +v 0.707107 0.707107 0.000000 +v 0.831470 0.555570 0.000000 +v 0.923880 0.382683 -0.000000 +v 0.980785 0.195090 0.000000 +v 1.000000 0.000000 0.000000 +v 0.980785 -0.195090 0.000000 +v 0.923880 -0.382683 -0.000000 +v 0.831470 -0.555570 0.000000 +v 0.707107 -0.707107 0.000000 +v 0.555570 -0.831470 0.000000 +v 0.382684 -0.923880 -0.000000 +v 0.195091 -0.980785 -0.000000 +v 0.191342 0.980785 0.038060 +v 0.375331 0.923880 0.074658 +v 0.544896 0.831470 0.108386 +v 0.693520 0.707107 0.137950 +v 0.815493 0.555570 0.162212 +v 0.906128 0.382683 0.180240 +v 0.961940 0.195090 0.191342 +v 0.980786 0.000000 0.195090 +v 0.961940 -0.195090 0.191342 +v 0.906128 -0.382683 0.180240 +v 0.815493 -0.555570 0.162212 +v 0.693520 -0.707107 0.137950 +v 0.544895 -0.831470 0.108386 +v 0.375331 -0.923880 0.074658 +v 0.191342 -0.980785 0.038060 +v 0.180240 0.980785 0.074658 +v 0.353554 0.923880 0.146447 +v 0.513280 0.831470 0.212608 +v 0.653282 0.707107 0.270598 +v 0.768178 0.555570 0.318190 +v 0.853554 0.382683 0.353553 +v 0.906127 0.195090 0.375330 +v 0.923880 0.000000 0.382684 +v 0.906127 -0.195090 0.375330 +v 0.853554 -0.382683 0.353553 +v 0.768178 -0.555570 0.318190 +v 0.653282 -0.707107 0.270598 +v 0.513280 -0.831470 0.212608 +v 0.353554 -0.923880 0.146447 +v 0.180240 -0.980785 0.074658 +v 0.162212 0.980785 0.108386 +v 0.318190 0.923880 0.212608 +v 0.461940 0.831470 0.308658 +v 0.587938 0.707107 0.392847 +v 0.691342 0.555570 0.461940 +v 0.768178 0.382683 0.513280 +v 0.815493 0.195090 0.544895 +v 0.831470 0.000000 0.555570 +v 0.815493 -0.195090 0.544895 +v 0.768178 -0.382683 0.513280 +v 0.691342 -0.555570 0.461940 +v 0.587938 -0.707107 0.392847 +v 0.461940 -0.831470 0.308658 +v 0.318190 -0.923880 0.212607 +v 0.162212 -0.980785 0.108386 +v 0.137950 0.980785 0.137950 +v 0.270598 0.923880 0.270598 +v 0.392848 0.831470 0.392848 +v 0.500000 0.707107 0.500000 +v 0.587938 0.555570 0.587938 +v 0.653282 0.382683 0.653281 +v 0.693520 0.195090 0.693520 +v 0.707107 0.000000 0.707107 +v 0.693520 -0.195090 0.693520 +v 0.653282 -0.382683 0.653281 +v 0.587938 -0.555570 0.587938 +v 0.500000 -0.707107 0.500000 +v 0.392848 -0.831470 0.392847 +v 0.270598 -0.923880 0.270598 +v 0.137950 -0.980785 0.137950 +v 0.108387 0.980785 0.162212 +v 0.212608 0.923880 0.318190 +v 0.308659 0.831470 0.461940 +v 0.392848 0.707107 0.587938 +v 0.461940 0.555570 0.691342 +v 0.513280 0.382683 0.768178 +v 0.544895 0.195090 0.815493 +v 0.555570 0.000000 0.831470 +v 0.544895 -0.195090 0.815493 +v 0.513280 -0.382683 0.768178 +v 0.461940 -0.555570 0.691342 +v 0.392848 -0.707107 0.587938 +v 0.308658 -0.831470 0.461940 +v 0.212608 -0.923880 0.318190 +v 0.108387 -0.980785 0.162212 +v 0.074658 0.980785 0.180240 +v 0.146447 0.923880 0.353553 +v 0.212608 0.831470 0.513280 +v 0.270598 0.707107 0.653281 +v 0.318190 0.555570 0.768177 +v 0.353554 0.382683 0.853553 +v 0.375330 0.195090 0.906127 +v 0.382684 0.000000 0.923880 +v 0.375330 -0.195090 0.906127 +v 0.353554 -0.382683 0.853553 +v 0.318190 -0.555570 0.768177 +v 0.270598 -0.707107 0.653281 +v 0.212608 -0.831470 0.513280 +v 0.146447 -0.923880 0.353553 +v 0.074658 -0.980785 0.180240 +v 0.038061 0.980785 0.191342 +v 0.074658 0.923880 0.375330 +v 0.108387 0.831470 0.544895 +v 0.137950 0.707107 0.693520 +v 0.162212 0.555570 0.815493 +v 0.180240 0.382683 0.906127 +v 0.191342 0.195090 0.961939 +v 0.195090 0.000000 0.980785 +v 0.191342 -0.195090 0.961939 +v 0.180240 -0.382683 0.906127 +v 0.162212 -0.555570 0.815493 +v 0.137950 -0.707107 0.693520 +v 0.108387 -0.831470 0.544895 +v 0.074658 -0.923880 0.375330 +v 0.038061 -0.980785 0.191342 +v 0.000000 0.980785 0.195090 +v 0.000000 0.923880 0.382683 +v 0.000000 0.831470 0.555570 +v 0.000000 0.707107 0.707107 +v 0.000000 0.555570 0.831469 +v 0.000000 0.382683 0.923879 +v 0.000000 0.195090 0.980785 +v 0.000000 0.000000 1.000000 +v 0.000000 -0.195090 0.980785 +v 0.000000 -0.382683 0.923879 +v 0.000000 -0.555570 0.831469 +v 0.000000 -0.707107 0.707107 +v 0.000000 -0.831470 0.555570 +v 0.000000 -0.923880 0.382683 +v 0.000000 -0.980785 0.195090 +v -0.038060 0.980785 0.191342 +v -0.074658 0.923880 0.375330 +v -0.108386 0.831470 0.544895 +v -0.137949 0.707107 0.693520 +v -0.162211 0.555570 0.815493 +v -0.180240 0.382683 0.906127 +v -0.191342 0.195090 0.961939 +v -0.195090 0.000000 0.980785 +v -0.191342 -0.195090 0.961939 +v -0.180240 -0.382683 0.906127 +v -0.162211 -0.555570 0.815493 +v -0.137949 -0.707107 0.693520 +v -0.108386 -0.831470 0.544895 +v -0.074658 -0.923880 0.375330 +v -0.038060 -0.980785 0.191342 +v 0.000000 1.000000 0.000000 +v -0.074658 0.980785 0.180240 +v -0.146446 0.923880 0.353553 +v -0.212607 0.831470 0.513280 +v -0.270598 0.707107 0.653281 +v -0.318189 0.555570 0.768177 +v -0.353553 0.382683 0.853553 +v -0.375330 0.195090 0.906127 +v -0.382683 0.000000 0.923879 +v -0.375330 -0.195090 0.906127 +v -0.353553 -0.382683 0.853553 +v -0.318189 -0.555570 0.768177 +v -0.270598 -0.707107 0.653281 +v -0.212607 -0.831470 0.513280 +v -0.146446 -0.923880 0.353553 +v -0.074657 -0.980785 0.180240 +v -0.108386 0.980785 0.162212 +v -0.212607 0.923880 0.318190 +v -0.308658 0.831470 0.461940 +v -0.392847 0.707107 0.587938 +v -0.461939 0.555570 0.691341 +v -0.513280 0.382683 0.768178 +v -0.544895 0.195090 0.815493 +v -0.555570 0.000000 0.831469 +v -0.544895 -0.195090 0.815493 +v -0.513280 -0.382683 0.768178 +v -0.461939 -0.555570 0.691341 +v -0.392847 -0.707107 0.587938 +v -0.308658 -0.831470 0.461940 +v -0.212607 -0.923880 0.318189 +v -0.108386 -0.980785 0.162212 +v -0.137949 0.980785 0.137950 +v -0.270598 0.923880 0.270598 +v -0.392847 0.831470 0.392847 +v -0.500000 0.707107 0.500000 +v -0.587937 0.555570 0.587937 +v -0.653281 0.382683 0.653281 +v -0.693519 0.195090 0.693519 +v -0.707106 0.000000 0.707106 +v -0.693519 -0.195090 0.693519 +v -0.653281 -0.382683 0.653281 +v -0.587937 -0.555570 0.587937 +v -0.500000 -0.707107 0.500000 +v -0.392847 -0.831470 0.392847 +v -0.270598 -0.923880 0.270598 +v -0.137949 -0.980785 0.137950 +v -0.162211 0.980785 0.108386 +v -0.318189 0.923880 0.212607 +v -0.461939 0.831470 0.308658 +v -0.587937 0.707107 0.392847 +v -0.691341 0.555570 0.461939 +v -0.768177 0.382683 0.513280 +v -0.815492 0.195090 0.544895 +v -0.831469 0.000000 0.555570 +v -0.815492 -0.195090 0.544895 +v -0.768177 -0.382683 0.513280 +v -0.691341 -0.555570 0.461939 +v -0.587937 -0.707107 0.392847 +v -0.461939 -0.831470 0.308658 +v -0.318189 -0.923880 0.212607 +v -0.162211 -0.980785 0.108386 +v -0.180240 0.980785 0.074658 +v -0.353553 0.923880 0.146447 +v -0.513280 0.831470 0.212607 +v -0.653281 0.707107 0.270598 +v -0.768177 0.555570 0.318189 +v -0.853553 0.382683 0.353553 +v -0.906127 0.195090 0.375330 +v -0.923879 0.000000 0.382683 +v -0.906127 -0.195090 0.375330 +v -0.853553 -0.382683 0.353553 +v -0.768177 -0.555570 0.318189 +v -0.653281 -0.707107 0.270598 +v -0.513279 -0.831470 0.212607 +v -0.353553 -0.923880 0.146446 +v -0.180240 -0.980785 0.074658 +v -0.191342 0.980785 0.038060 +v -0.375330 0.923880 0.074658 +v -0.544895 0.831470 0.108386 +v -0.693520 0.707107 0.137950 +v -0.815492 0.555570 0.162211 +v -0.906127 0.382683 0.180240 +v -0.961939 0.195090 0.191341 +v -0.980785 0.000000 0.195090 +v -0.961939 -0.195090 0.191341 +v -0.906127 -0.382683 0.180240 +v -0.815492 -0.555570 0.162211 +v -0.693520 -0.707107 0.137950 +v -0.544895 -0.831470 0.108386 +v -0.375330 -0.923880 0.074658 +v -0.191341 -0.980785 0.038060 +vt 0.413875 0.675122 +vt 0.449359 0.665434 +vt 0.455825 0.686567 +vt 0.420191 0.698248 +vt 0.642354 0.109088 +vt 0.631480 0.144773 +vt 0.618058 0.139213 +vt 0.635686 0.106335 +vt 0.645773 0.295317 +vt 0.649440 0.258211 +vt 0.656655 0.258198 +vt 0.660289 0.295311 +vt 0.139657 0.687920 +vt 0.180348 0.693043 +vt 0.177265 0.719279 +vt 0.135337 0.712632 +vt 0.214689 0.695696 +vt 0.245172 0.696631 +vt 0.244973 0.724201 +vt 0.212998 0.722841 +vt 0.273508 0.696188 +vt 0.300612 0.694560 +vt 0.303117 0.721926 +vt 0.274691 0.723821 +vt 0.327278 0.691779 +vt 0.354440 0.687784 +vt 0.359271 0.713688 +vt 0.331044 0.718572 +vt 0.382903 0.682353 +vt 0.388617 0.707050 +vt 0.493909 0.651908 +vt 0.499572 0.670757 +vt 0.086965 0.678736 +vt 0.081865 0.701107 +vt 0.275999 0.752982 +vt 0.244508 0.753270 +vt 0.335606 0.746653 +vt 0.306115 0.750746 +vt 0.395616 0.732473 +vt 0.365187 0.740638 +vt 0.463609 0.707655 +vt 0.427887 0.721723 +vt 0.605979 0.131142 +vt 0.629682 0.102335 +vt 0.663729 0.256778 +vt 0.674528 0.292474 +vt 0.173264 0.746580 +vt 0.129903 0.738009 +vt 0.210715 0.751323 +vt 0.506307 0.689074 +vt 0.075702 0.723650 +vt 0.277455 0.784096 +vt 0.243690 0.784236 +vt 0.341214 0.776366 +vt 0.309741 0.781425 +vt 0.404241 0.758757 +vt 0.372495 0.768883 +vt 0.472984 0.728594 +vt 0.437288 0.745565 +vt 0.595707 0.120869 +vt 0.624574 0.097240 +vt 0.670391 0.254007 +vt 0.687943 0.286915 +vt 0.168064 0.775161 +vt 0.123072 0.764112 +vt 0.207618 0.781482 +vt 0.514299 0.706733 +vt 0.068278 0.746289 +vt 0.279081 0.817739 +vt 0.242366 0.817639 +vt 0.348207 0.808160 +vt 0.314186 0.814505 +vt 0.414952 0.786046 +vt 0.381628 0.798727 +vt 0.484274 0.749233 +vt 0.448817 0.769753 +vt 0.587636 0.108790 +vt 0.620558 0.091246 +vt 0.676384 0.249989 +vt 0.700016 0.278845 +vt 0.161265 0.805277 +vt 0.114455 0.790984 +vt 0.203395 0.813745 +vt 0.523739 0.723557 +vt 0.059352 0.768895 +vt 0.280901 0.854704 +vt 0.240298 0.854215 +vt 0.357071 0.842624 +vt 0.319730 0.850726 +vt 0.428378 0.814471 +vt 0.393192 0.830548 +vt 0.497858 0.769339 +vt 0.463021 0.794196 +vt 0.582076 0.095368 +vt 0.617789 0.084584 +vt 0.681478 0.244881 +vt 0.710285 0.268574 +vt 0.152290 0.837221 +vt 0.103529 0.818622 +vt 0.197585 0.848677 +vt 0.534809 0.739299 +vt 0.048635 0.791259 +vt 0.282937 0.896126 +vt 0.237105 0.894997 +vt 0.368527 0.880555 +vt 0.326788 0.891129 +vt 0.445392 0.844120 +vt 0.408069 0.864797 +vt 0.514166 0.788539 +vt 0.480603 0.818681 +vt 0.579242 0.081120 +vt 0.616372 0.077510 +vt 0.685478 0.238877 +vt 0.718354 0.256497 +vt 0.140300 0.871323 +vt 0.089582 0.846929 +vt 0.189484 0.887024 +vt 0.547669 0.753624 +vt 0.035794 0.813051 +vt 0.285208 0.943670 +vt 0.232161 0.941477 +vt 0.383687 0.923048 +vt 0.336009 0.937229 +vt 0.467223 0.874959 +vt 0.427576 0.902004 +vt 0.533656 0.806253 +vt 0.502460 0.842768 +vt 0.579242 0.066592 +vt 0.616363 0.070296 +vt 0.688230 0.232208 +vt 0.723912 0.243077 +vt 0.124052 0.907917 +vt 0.071642 0.875639 +vt 0.177991 0.929789 +vt 0.562423 0.766088 +vt 0.020464 0.833766 +vt 0.287619 0.999894 +vt 0.224318 0.995850 +vt 0.404258 0.971672 +vt 0.348354 0.991334 +vt 0.495551 0.906701 +vt 0.453665 0.942769 +vt 0.556709 0.821600 +vt 0.529651 0.865631 +vt 0.582076 0.052344 +vt 0.617761 0.063218 +vt 0.689628 0.225130 +vt 0.726746 0.228831 +vt 0.101642 0.947212 +vt 0.048362 0.904153 +vt 0.161266 0.978279 +vt 0.579031 0.776103 +vt 0.002303 0.852641 +vt 0.124744 0.058158 +vt 0.174238 0.028911 +vt 0.195088 0.077674 +vt 0.151106 0.098962 +vt 0.230346 0.008928 +vt 0.291397 0.000106 +vt 0.293989 0.056651 +vt 0.242938 0.063272 +vt 0.355114 0.003982 +vt 0.418655 0.021518 +vt 0.401905 0.070385 +vt 0.347356 0.058727 +vt 0.478791 0.052708 +vt 0.532555 0.096052 +vt 0.509109 0.124815 +vt 0.456264 0.092335 +vt 0.587636 0.038922 +vt 0.620514 0.056549 +vt 0.689618 0.217915 +vt 0.726745 0.214305 +vt 0.022117 0.180174 +vt 0.048930 0.135927 +vt 0.076289 0.158677 +vt 0.045270 0.195385 +vt 0.082886 0.094563 +vt 0.111447 0.126255 +vt 0.579031 0.147968 +vt 0.560728 0.167010 +vt 0.000106 0.225804 +vt 0.016774 0.235706 +vt 0.210444 0.120293 +vt 0.170812 0.136221 +vt 0.296382 0.104448 +vt 0.252329 0.109567 +vt 0.390397 0.113451 +vt 0.342470 0.105498 +vt 0.491044 0.153758 +vt 0.439933 0.129209 +vt 0.595707 0.026843 +vt 0.624514 0.050545 +vt 0.688201 0.210841 +vt 0.723912 0.200057 +vt 0.098280 0.182690 +vt 0.064853 0.212993 +vt 0.133449 0.157077 +vt 0.545278 0.187903 +vt 0.031598 0.248063 +vt 0.222035 0.158336 +vt 0.185834 0.170530 +vt 0.298498 0.146075 +vt 0.259501 0.150133 +vt 0.382282 0.152047 +vt 0.339312 0.146516 +vt 0.476995 0.182282 +vt 0.427879 0.163553 +vt 0.605980 0.016570 +vt 0.629609 0.045437 +vt 0.685432 0.204180 +vt 0.718353 0.186636 +vt 0.115961 0.207126 +vt 0.081240 0.232106 +vt 0.150582 0.186726 +vt 0.532331 0.209878 +vt 0.044531 0.262282 +vt 0.230990 0.192905 +vt 0.197510 0.202416 +vt 0.300363 0.183213 +vt 0.265115 0.186495 +vt 0.376451 0.187189 +vt 0.337259 0.183288 +vt 0.465981 0.210120 +vt 0.418847 0.195709 +vt 0.618059 0.008499 +vt 0.635603 0.041421 +vt 0.681416 0.198186 +vt 0.710283 0.174557 +vt 0.130229 0.231533 +vt 0.094883 0.252135 +vt 0.164070 0.215155 +vt 0.521516 0.232426 +vt 0.055671 0.277911 +vt 0.238038 0.224801 +vt 0.206753 0.232348 +vt 0.302008 0.217003 +vt 0.269597 0.219698 +vt 0.372201 0.219633 +vt 0.335933 0.216858 +vt 0.457280 0.237178 +vt 0.411991 0.226011 +vt 0.631481 0.002940 +vt 0.642265 0.038652 +vt 0.676308 0.193091 +vt 0.700011 0.164285 +vt 0.141791 0.255695 +vt 0.106208 0.272707 +vt 0.174766 0.242427 +vt 0.512493 0.255216 +vt 0.065171 0.294606 +vt 0.243626 0.254564 +vt 0.213962 0.260564 +vt 0.303457 0.248240 +vt 0.273221 0.250472 +vt 0.369070 0.249949 +vt 0.335093 0.247968 +vt 0.450364 0.263452 +vt 0.406735 0.254757 +vt 0.645729 0.000106 +vt 0.649339 0.037236 +vt 0.670304 0.189091 +vt 0.687932 0.156213 +vt 0.151222 0.279544 +vt 0.115591 0.293589 +vt 0.183471 0.268804 +vt 0.504967 0.278037 +vt 0.073205 0.312109 +vt 0.248140 0.282701 +vt 0.219774 0.287547 +vt 0.304740 0.277512 +vt 0.276196 0.279379 +vt 0.366750 0.278569 +vt 0.334589 0.277164 +vt 0.444842 0.288986 +vt 0.402676 0.282204 +vt 0.660257 0.000106 +vt 0.656553 0.037226 +vt 0.663636 0.186338 +vt 0.674510 0.150653 +vt 0.158906 0.303026 +vt 0.123341 0.314630 +vt 0.190531 0.294276 +vt 0.498690 0.300758 +vt 0.079941 0.330228 +vt 0.251864 0.309582 +vt 0.224654 0.313565 +vt 0.305886 0.305255 +vt 0.278678 0.306843 +vt 0.365035 0.305832 +vt 0.334324 0.304858 +vt 0.440424 0.313841 +vt 0.399533 0.308566 +vt 0.674505 0.002940 +vt 0.663631 0.038625 +vt 0.656558 0.184940 +vt 0.660262 0.147819 +vt 0.165158 0.326151 +vt 0.129723 0.335749 +vt 0.196140 0.318970 +vt 0.493461 0.323300 +vt 0.085542 0.348828 +vt 0.254937 0.335440 +vt 0.228658 0.338701 +vt 0.306921 0.331793 +vt 0.280768 0.333161 +vt 0.363783 0.331998 +vt 0.334236 0.331359 +vt 0.436895 0.338087 +vt 0.397107 0.334024 +vt 0.687927 0.008499 +vt 0.670300 0.041377 +vt 0.649343 0.184949 +vt 0.645734 0.147818 +vt 0.170264 0.348988 +vt 0.134959 0.356908 +vt 0.200681 0.343092 +vt 0.489117 0.345619 +vt 0.090153 0.367812 +vt 0.257455 0.360466 +vt 0.231793 0.363134 +vt 0.307866 0.357374 +vt 0.282538 0.358565 +vt 0.362896 0.357277 +vt 0.334285 0.356908 +vt 0.434097 0.361793 +vt 0.395256 0.358727 +vt 0.700006 0.016571 +vt 0.676304 0.045378 +vt 0.642269 0.186366 +vt 0.631484 0.150652 +vt 0.174445 0.371588 +vt 0.139230 0.378090 +vt 0.204517 0.366766 +vt 0.485530 0.367694 +vt 0.093900 0.387107 +vt 0.259557 0.384866 +vt 0.234397 0.387075 +vt 0.308757 0.382202 +vt 0.284062 0.383260 +vt 0.362311 0.381840 +vt 0.334445 0.381700 +vt 0.431915 0.385025 +vt 0.393883 0.382804 +vt 0.710279 0.026843 +vt 0.681412 0.050473 +vt 0.635607 0.189135 +vt 0.618062 0.156211 +vt 0.177839 0.393986 +vt 0.142678 0.399292 +vt 0.207632 0.390049 +vt 0.482600 0.389519 +vt 0.096891 0.406664 +vt 0.261331 0.408774 +vt 0.236520 0.410628 +vt 0.309643 0.406441 +vt 0.285398 0.407405 +vt 0.361989 0.405822 +vt 0.334686 0.405903 +vt 0.430264 0.407843 +vt 0.392922 0.406359 +vt 0.718350 0.038923 +vt 0.685428 0.056466 +vt 0.629613 0.193151 +vt 0.605982 0.164283 +vt 0.180565 0.416240 +vt 0.145417 0.420521 +vt 0.210193 0.413049 +vt 0.480251 0.411094 +vt 0.099215 0.426447 +vt 0.262864 0.432337 +vt 0.238462 0.433873 +vt 0.310382 0.430277 +vt 0.286569 0.431150 +vt 0.361918 0.429338 +vt 0.335106 0.429606 +vt 0.429089 0.430305 +vt 0.392329 0.429489 +vt 0.723909 0.052344 +vt 0.688197 0.063128 +vt 0.624518 0.198259 +vt 0.595708 0.174556 +vt 0.182706 0.438404 +vt 0.147540 0.441798 +vt 0.212077 0.435853 +vt 0.478426 0.432427 +vt 0.100946 0.446435 +vt 0.264155 0.455636 +vt 0.239894 0.456920 +vt 0.311168 0.453746 +vt 0.287629 0.454589 +vt 0.362079 0.452503 +vt 0.335622 0.452979 +vt 0.428351 0.452460 +vt 0.392079 0.452275 +vt 0.726743 0.066593 +vt 0.689613 0.070202 +vt 0.620517 0.204263 +vt 0.587636 0.186636 +vt 0.184378 0.460537 +vt 0.149125 0.463143 +vt 0.213744 0.458520 +vt 0.477087 0.453526 +vt 0.102140 0.466612 +vt 0.265281 0.478777 +vt 0.241103 0.479865 +vt 0.312000 0.476979 +vt 0.288626 0.477827 +vt 0.362475 0.475404 +vt 0.336265 0.476105 +vt 0.428035 0.474356 +vt 0.392164 0.474793 +vt 0.726743 0.081121 +vt 0.689623 0.077417 +vt 0.617765 0.210933 +vt 0.582076 0.200059 +vt 0.185629 0.482679 +vt 0.150225 0.484581 +vt 0.215033 0.481137 +vt 0.476212 0.474400 +vt 0.102842 0.486968 +vt 0.266286 0.501853 +vt 0.242109 0.502784 +vt 0.312900 0.500079 +vt 0.289595 0.500961 +vt 0.363121 0.498120 +vt 0.337064 0.499070 +vt 0.428137 0.496034 +vt 0.392591 0.497104 +vt 0.723909 0.095369 +vt 0.688224 0.084495 +vt 0.616366 0.218011 +vt 0.579242 0.214310 +vt 0.186498 0.504891 +vt 0.150880 0.506140 +vt 0.216010 0.503776 +vt 0.475791 0.495057 +vt 0.103080 0.507500 +vt 0.267205 0.524951 +vt 0.242941 0.525759 +vt 0.313895 0.523137 +vt 0.290569 0.524086 +vt 0.364043 0.520726 +vt 0.338048 0.521960 +vt 0.428671 0.517529 +vt 0.393378 0.519270 +vt 0.718349 0.108791 +vt 0.685472 0.091164 +vt 0.616376 0.225226 +vt 0.579243 0.228840 +vt 0.187015 0.527227 +vt 0.151114 0.527854 +vt 0.216717 0.526506 +vt 0.475829 0.515500 +vt 0.102868 0.528208 +vt 0.268068 0.548164 +vt 0.243622 0.548875 +vt 0.315019 0.546244 +vt 0.291579 0.547294 +vt 0.365276 0.543296 +vt 0.339256 0.544859 +vt 0.429666 0.538876 +vt 0.394560 0.541348 +vt 0.710278 0.120870 +vt 0.681471 0.097167 +vt 0.617793 0.232300 +vt 0.582078 0.243091 +vt 0.187196 0.549748 +vt 0.150936 0.549761 +vt 0.217179 0.549405 +vt 0.476346 0.535730 +vt 0.102207 0.549098 +vt 0.268903 0.571588 +vt 0.244174 0.572226 +vt 0.316305 0.569489 +vt 0.292659 0.570680 +vt 0.366870 0.565904 +vt 0.340737 0.567856 +vt 0.431166 0.560106 +vt 0.396183 0.563392 +vt 0.700006 0.131142 +vt 0.676376 0.102275 +vt 0.620564 0.238962 +vt 0.587641 0.256515 +vt 0.187048 0.572519 +vt 0.150340 0.571902 +vt 0.217409 0.572550 +vt 0.477375 0.555742 +vt 0.101083 0.570176 +vt 0.269737 0.595329 +vt 0.244609 0.595910 +vt 0.317774 0.592953 +vt 0.293848 0.594346 +vt 0.368885 0.588631 +vt 0.342559 0.591058 +vt 0.433231 0.581247 +vt 0.398310 0.585460 +vt 0.687926 0.139214 +vt 0.670383 0.106291 +vt 0.624581 0.244954 +vt 0.595716 0.268597 +vt 0.186561 0.595612 +vt 0.149307 0.594322 +vt 0.217413 0.596035 +vt 0.478965 0.575528 +vt 0.099469 0.591453 +vt 0.270595 0.619514 +vt 0.244930 0.620047 +vt 0.319644 0.616789 +vt 0.295214 0.618433 +vt 0.371388 0.611539 +vt 0.344719 0.614519 +vt 0.435940 0.602325 +vt 0.401021 0.607604 +vt 0.674505 0.144773 +vt 0.663721 0.109061 +vt 0.629690 0.250048 +vt 0.605996 0.278872 +vt 0.185708 0.619108 +vt 0.147796 0.617072 +vt 0.217184 0.619959 +vt 0.481183 0.595069 +vt 0.097322 0.612939 +vt 0.271489 0.644279 +vt 0.245122 0.644772 +vt 0.321847 0.641155 +vt 0.296769 0.643067 +vt 0.374481 0.634715 +vt 0.347371 0.638342 +vt 0.439395 0.623368 +vt 0.404414 0.629882 +vt 0.660256 0.147607 +vt 0.656647 0.110477 +vt 0.635695 0.254045 +vt 0.618085 0.286943 +vt 0.184446 0.643100 +vt 0.145748 0.640212 +vt 0.216710 0.644439 +vt 0.484116 0.614340 +vt 0.094579 0.634644 +vt 0.272441 0.669771 +vt 0.245130 0.670275 +vt 0.324325 0.666098 +vt 0.298537 0.668374 +vt 0.378300 0.658277 +vt 0.350671 0.662754 +vt 0.443719 0.644412 +vt 0.408616 0.652358 +vt 0.645729 0.147607 +vt 0.649432 0.110486 +vt 0.642365 0.256793 +vt 0.631519 0.292500 +vt 0.182701 0.667696 +vt 0.143075 0.663803 +vt 0.215982 0.669600 +vt 0.487877 0.633305 +vt 0.091160 0.656576 +vt 0.652993 0.073856 +vt 0.652998 0.221570 +vn -0.633200 0.771500 -0.062400 +vn -0.290200 -0.956500 -0.028600 +vn -0.290200 0.956500 -0.028600 +vn -0.633200 -0.771500 -0.062400 +vn -0.878600 -0.469600 -0.086500 +vn -0.990400 -0.097500 -0.097500 +vn -0.952700 0.289000 -0.093800 +vn -0.770800 0.632600 -0.075900 +vn -0.470900 0.881000 -0.046400 +vn -0.470900 -0.881000 -0.046400 +vn -0.770800 -0.632600 -0.075900 +vn -0.952700 -0.289000 -0.093800 +vn -0.990400 0.097500 -0.097500 +vn -0.878600 0.469600 -0.086500 +vn -0.916100 -0.289000 -0.277900 +vn -0.952400 0.097500 -0.288900 +vn -0.844800 0.469600 -0.256300 +vn -0.608800 0.771500 -0.184700 +vn -0.279000 -0.956500 -0.084600 +vn -0.279000 0.956500 -0.084600 +vn -0.608800 -0.771500 -0.184700 +vn -0.844800 -0.469600 -0.256300 +vn -0.952400 -0.097500 -0.288900 +vn -0.916100 0.289000 -0.277900 +vn -0.741200 0.632600 -0.224800 +vn -0.452800 0.881000 -0.137400 +vn -0.452800 -0.881000 -0.137400 +vn -0.741200 -0.632600 -0.224800 +vn -0.844300 -0.289000 -0.451300 +vn -0.877700 0.097500 -0.469100 +vn -0.778600 0.469600 -0.416200 +vn -0.561100 0.771500 -0.299900 +vn -0.257100 -0.956500 -0.137400 +vn -0.257100 0.956500 -0.137400 +vn -0.561100 -0.771500 -0.299900 +vn -0.778600 -0.469600 -0.416200 +vn -0.877700 -0.097500 -0.469100 +vn -0.844300 0.289000 -0.451300 +vn -0.683100 0.632600 -0.365100 +vn -0.417300 0.881000 -0.223100 +vn -0.417300 -0.881000 -0.223100 +vn -0.683100 -0.632600 -0.365100 +vn -0.740000 -0.289000 -0.607300 +vn -0.769300 0.097600 -0.631400 +vn -0.682500 0.469600 -0.560100 +vn -0.491800 0.771500 -0.403600 +vn -0.225400 -0.956500 -0.185000 +vn -0.225400 0.956500 -0.185000 +vn -0.491800 -0.771500 -0.403600 +vn -0.682500 -0.469600 -0.560100 +vn -0.769300 -0.097600 -0.631400 +vn -0.740000 0.289000 -0.607300 +vn -0.598700 0.632600 -0.491300 +vn -0.365800 0.881000 -0.300200 +vn -0.365800 -0.881000 -0.300200 +vn -0.598700 -0.632600 -0.491300 +vn -0.607300 -0.289000 -0.740000 +vn -0.631400 0.097600 -0.769300 +vn -0.560100 0.469600 -0.682500 +vn -0.403600 0.771500 -0.491800 +vn -0.185000 -0.956500 -0.225400 +vn -0.185000 0.956500 -0.225400 +vn -0.403600 -0.771500 -0.491800 +vn -0.560100 -0.469600 -0.682500 +vn -0.631400 -0.097600 -0.769300 +vn -0.607300 0.289000 -0.740000 +vn -0.491300 0.632600 -0.598700 +vn -0.300200 0.881000 -0.365800 +vn -0.300200 -0.881000 -0.365800 +vn -0.491300 -0.632600 -0.598700 +vn -0.451300 -0.289000 -0.844300 +vn -0.469100 0.097600 -0.877700 +vn -0.416200 0.469600 -0.778600 +vn -0.299900 0.771500 -0.561100 +vn -0.137400 -0.956500 -0.257100 +vn -0.137400 0.956500 -0.257100 +vn -0.299900 -0.771500 -0.561100 +vn -0.416200 -0.469600 -0.778600 +vn -0.469100 -0.097600 -0.877700 +vn -0.451300 0.289000 -0.844300 +vn -0.365100 0.632600 -0.683100 +vn -0.223000 0.881000 -0.417300 +vn -0.223000 -0.881000 -0.417300 +vn -0.365100 -0.632600 -0.683100 +vn -0.277900 -0.289000 -0.916100 +vn -0.288900 0.097600 -0.952400 +vn -0.256300 0.469600 -0.844800 +vn -0.184700 0.771500 -0.608800 +vn -0.084600 -0.956500 -0.279000 +vn -0.084600 0.956500 -0.279000 +vn -0.184700 -0.771500 -0.608800 +vn -0.256300 -0.469600 -0.844800 +vn -0.288900 -0.097600 -0.952400 +vn -0.277900 0.289000 -0.916100 +vn -0.224800 0.632600 -0.741200 +vn -0.137400 0.881000 -0.452800 +vn -0.137400 -0.881000 -0.452800 +vn -0.224800 -0.632600 -0.741200 +vn -0.093800 -0.289000 -0.952700 +vn -0.097500 0.097600 -0.990400 +vn -0.086500 0.469600 -0.878600 +vn -0.062400 0.771500 -0.633200 +vn -0.028600 -0.956500 -0.290200 +vn -0.028600 0.956500 -0.290200 +vn -0.062400 -0.771500 -0.633200 +vn -0.086500 -0.469600 -0.878600 +vn -0.097500 -0.097600 -0.990400 +vn -0.093800 0.289000 -0.952700 +vn -0.075900 0.632600 -0.770800 +vn -0.046400 0.881000 -0.470900 +vn -0.046400 -0.881000 -0.470900 +vn -0.075900 -0.632600 -0.770800 +vn 0.093800 -0.289000 -0.952700 +vn 0.097500 0.097600 -0.990400 +vn 0.086500 0.469600 -0.878600 +vn 0.062400 0.771500 -0.633200 +vn 0.028600 -0.956500 -0.290200 +vn 0.028600 0.956500 -0.290200 +vn 0.062400 -0.771500 -0.633200 +vn 0.086500 -0.469600 -0.878600 +vn 0.097500 -0.097600 -0.990400 +vn 0.093800 0.289000 -0.952700 +vn 0.075900 0.632600 -0.770800 +vn 0.046400 0.881000 -0.470900 +vn 0.046400 -0.881000 -0.470900 +vn 0.075900 -0.632600 -0.770800 +vn 0.277900 -0.289000 -0.916100 +vn 0.288900 0.097600 -0.952400 +vn 0.256300 0.469600 -0.844800 +vn 0.184700 0.771500 -0.608800 +vn 0.084600 -0.956500 -0.279000 +vn 0.084600 0.956500 -0.279000 +vn 0.184700 -0.771500 -0.608800 +vn 0.256300 -0.469600 -0.844800 +vn 0.288900 -0.097600 -0.952400 +vn 0.277900 0.289000 -0.916100 +vn 0.224800 0.632600 -0.741200 +vn 0.137400 0.881000 -0.452800 +vn 0.137400 -0.881000 -0.452800 +vn 0.224800 -0.632600 -0.741200 +vn 0.451300 -0.289000 -0.844300 +vn 0.469100 0.097600 -0.877700 +vn 0.416200 0.469600 -0.778600 +vn 0.299900 0.771500 -0.561100 +vn 0.137400 -0.956500 -0.257100 +vn 0.137400 0.956500 -0.257100 +vn 0.299900 -0.771500 -0.561100 +vn 0.416200 -0.469600 -0.778600 +vn 0.469100 -0.097600 -0.877700 +vn 0.451300 0.289000 -0.844300 +vn 0.365100 0.632600 -0.683100 +vn 0.223000 0.881000 -0.417300 +vn 0.223000 -0.881000 -0.417300 +vn 0.365100 -0.632600 -0.683100 +vn 0.607300 -0.289000 -0.740000 +vn 0.631400 0.097600 -0.769300 +vn 0.560100 0.469600 -0.682500 +vn 0.403600 0.771500 -0.491800 +vn 0.185000 -0.956500 -0.225400 +vn 0.185000 0.956500 -0.225400 +vn 0.403600 -0.771500 -0.491800 +vn 0.560100 -0.469600 -0.682500 +vn 0.631400 -0.097600 -0.769300 +vn 0.607300 0.289000 -0.740000 +vn 0.491300 0.632600 -0.598700 +vn 0.300200 0.881000 -0.365800 +vn 0.300200 -0.881000 -0.365800 +vn 0.491300 -0.632600 -0.598700 +vn 0.740000 -0.289000 -0.607300 +vn 0.769300 0.097600 -0.631400 +vn 0.682500 0.469600 -0.560100 +vn 0.491800 0.771500 -0.403600 +vn 0.225400 -0.956500 -0.185000 +vn 0.225400 0.956500 -0.185000 +vn 0.491800 -0.771500 -0.403600 +vn 0.682500 -0.469600 -0.560100 +vn 0.769300 -0.097600 -0.631400 +vn 0.740000 0.289000 -0.607300 +vn 0.598700 0.632600 -0.491300 +vn 0.365800 0.881000 -0.300200 +vn 0.365800 -0.881000 -0.300200 +vn 0.598700 -0.632600 -0.491300 +vn 0.844300 -0.289000 -0.451300 +vn 0.877700 0.097600 -0.469100 +vn 0.778600 0.469600 -0.416200 +vn 0.561100 0.771500 -0.299900 +vn 0.257100 -0.956500 -0.137400 +vn 0.257100 0.956500 -0.137400 +vn 0.561100 -0.771500 -0.299900 +vn 0.778600 -0.469600 -0.416200 +vn 0.877700 -0.097600 -0.469100 +vn 0.844300 0.289000 -0.451300 +vn 0.683100 0.632600 -0.365100 +vn 0.417300 0.881000 -0.223100 +vn 0.417300 -0.881000 -0.223000 +vn 0.683100 -0.632600 -0.365100 +vn 0.916100 -0.289000 -0.277900 +vn 0.952400 0.097600 -0.288900 +vn 0.844800 0.469600 -0.256300 +vn 0.608800 0.771500 -0.184700 +vn 0.279000 -0.956500 -0.084600 +vn 0.279000 0.956500 -0.084600 +vn 0.608800 -0.771500 -0.184700 +vn 0.844800 -0.469600 -0.256300 +vn 0.952400 -0.097600 -0.288900 +vn 0.916100 0.289000 -0.277900 +vn 0.741200 0.632600 -0.224800 +vn 0.452800 0.881000 -0.137400 +vn 0.452800 -0.881000 -0.137400 +vn 0.741200 -0.632600 -0.224800 +vn 0.952700 -0.289000 -0.093800 +vn 0.990400 0.097600 -0.097500 +vn 0.878600 0.469600 -0.086500 +vn 0.633200 0.771500 -0.062400 +vn 0.290200 -0.956500 -0.028600 +vn 0.290200 0.956500 -0.028600 +vn 0.633200 -0.771500 -0.062400 +vn 0.878600 -0.469600 -0.086500 +vn 0.990400 -0.097600 -0.097500 +vn 0.952700 0.289000 -0.093800 +vn 0.770800 0.632600 -0.075900 +vn 0.470900 0.881000 -0.046400 +vn 0.470900 -0.881000 -0.046400 +vn 0.770800 -0.632600 -0.075900 +vn 0.952700 -0.289000 0.093800 +vn 0.990400 0.097600 0.097500 +vn 0.878600 0.469600 0.086500 +vn 0.633200 0.771500 0.062400 +vn 0.290200 -0.956500 0.028600 +vn 0.290200 0.956500 0.028600 +vn 0.633200 -0.771500 0.062400 +vn 0.878600 -0.469600 0.086500 +vn 0.990400 -0.097600 0.097500 +vn 0.952700 0.289000 0.093800 +vn 0.770800 0.632600 0.075900 +vn 0.470900 0.881000 0.046400 +vn 0.470900 -0.881000 0.046400 +vn 0.770800 -0.632600 0.075900 +vn 0.916100 -0.289000 0.277900 +vn 0.952400 0.097600 0.288900 +vn 0.844800 0.469600 0.256300 +vn 0.608800 0.771500 0.184700 +vn 0.279000 -0.956500 0.084600 +vn 0.279000 0.956500 0.084600 +vn 0.608800 -0.771500 0.184700 +vn 0.844800 -0.469600 0.256300 +vn 0.952400 -0.097600 0.288900 +vn 0.916100 0.289000 0.277900 +vn 0.741200 0.632600 0.224800 +vn 0.452800 0.881000 0.137400 +vn 0.452800 -0.881000 0.137400 +vn 0.741200 -0.632600 0.224800 +vn 0.844300 -0.289000 0.451300 +vn 0.877700 0.097600 0.469100 +vn 0.778600 0.469600 0.416200 +vn 0.561100 0.771500 0.299900 +vn 0.257100 -0.956500 0.137400 +vn 0.257100 0.956500 0.137400 +vn 0.561100 -0.771500 0.299900 +vn 0.778600 -0.469600 0.416200 +vn 0.877700 -0.097600 0.469100 +vn 0.844300 0.289000 0.451300 +vn 0.683100 0.632600 0.365100 +vn 0.417300 0.881000 0.223100 +vn 0.417300 -0.881000 0.223100 +vn 0.683100 -0.632600 0.365100 +vn 0.740000 -0.289000 0.607300 +vn 0.769300 0.097600 0.631400 +vn 0.682500 0.469600 0.560100 +vn 0.491800 0.771500 0.403600 +vn 0.225400 -0.956500 0.185000 +vn 0.225400 0.956500 0.185000 +vn 0.491800 -0.771500 0.403600 +vn 0.682500 -0.469600 0.560100 +vn 0.769300 -0.097600 0.631400 +vn 0.740000 0.289000 0.607300 +vn 0.598700 0.632600 0.491300 +vn 0.365800 0.881000 0.300200 +vn 0.365800 -0.881000 0.300200 +vn 0.598700 -0.632600 0.491300 +vn 0.607300 -0.289000 0.740000 +vn 0.631400 0.097600 0.769300 +vn 0.560100 0.469600 0.682500 +vn 0.403600 0.771500 0.491800 +vn 0.185000 -0.956500 0.225400 +vn 0.185000 0.956500 0.225400 +vn 0.403600 -0.771500 0.491800 +vn 0.560100 -0.469600 0.682500 +vn 0.631400 -0.097600 0.769300 +vn 0.607300 0.289000 0.740000 +vn 0.491300 0.632600 0.598700 +vn 0.300200 0.881000 0.365800 +vn 0.300200 -0.881000 0.365800 +vn 0.491300 -0.632600 0.598700 +vn 0.451300 -0.289000 0.844300 +vn 0.469100 0.097600 0.877700 +vn 0.416200 0.469600 0.778600 +vn 0.299900 0.771500 0.561100 +vn 0.137400 -0.956500 0.257100 +vn 0.137400 0.956500 0.257100 +vn 0.299900 -0.771500 0.561100 +vn 0.416200 -0.469600 0.778600 +vn 0.469100 -0.097600 0.877700 +vn 0.451300 0.289000 0.844300 +vn 0.365100 0.632600 0.683100 +vn 0.223000 0.881000 0.417300 +vn 0.223000 -0.881000 0.417300 +vn 0.365100 -0.632600 0.683100 +vn 0.277900 -0.289000 0.916100 +vn 0.288900 0.097600 0.952400 +vn 0.256300 0.469600 0.844800 +vn 0.184700 0.771500 0.608800 +vn 0.084600 -0.956500 0.279000 +vn 0.084600 0.956500 0.279000 +vn 0.184700 -0.771500 0.608800 +vn 0.256300 -0.469600 0.844800 +vn 0.288900 -0.097600 0.952400 +vn 0.277900 0.289000 0.916100 +vn 0.224800 0.632600 0.741200 +vn 0.137400 0.881000 0.452800 +vn 0.137400 -0.881000 0.452800 +vn 0.224800 -0.632600 0.741200 +vn 0.093800 -0.289000 0.952700 +vn 0.097500 0.097600 0.990400 +vn 0.086500 0.469600 0.878600 +vn 0.062400 0.771500 0.633200 +vn 0.028600 -0.956500 0.290200 +vn 0.028600 0.956500 0.290200 +vn 0.062400 -0.771500 0.633200 +vn 0.086500 -0.469600 0.878600 +vn 0.097500 -0.097600 0.990400 +vn 0.093800 0.289000 0.952700 +vn 0.075900 0.632600 0.770800 +vn 0.046400 0.881000 0.470900 +vn 0.046400 -0.881000 0.470900 +vn 0.075900 -0.632600 0.770800 +vn -0.093800 -0.289000 0.952700 +vn -0.097600 0.097600 0.990400 +vn -0.086500 0.469600 0.878600 +vn -0.062400 0.771500 0.633200 +vn -0.028600 -0.956500 0.290200 +vn -0.028600 0.956500 0.290200 +vn -0.062400 -0.771500 0.633200 +vn -0.086500 -0.469600 0.878600 +vn -0.097600 -0.097600 0.990400 +vn -0.093800 0.289000 0.952700 +vn -0.075900 0.632600 0.770800 +vn -0.046400 0.881000 0.470900 +vn -0.046400 -0.881000 0.470900 +vn -0.075900 -0.632600 0.770800 +vn -0.277900 -0.289000 0.916100 +vn -0.288900 0.097600 0.952400 +vn -0.256300 0.469600 0.844800 +vn -0.184700 0.771500 0.608800 +vn -0.084600 -0.956500 0.279000 +vn -0.084600 0.956500 0.279000 +vn -0.184700 -0.771500 0.608800 +vn -0.256300 -0.469600 0.844800 +vn -0.288900 -0.097600 0.952400 +vn -0.277900 0.289000 0.916100 +vn -0.224800 0.632600 0.741200 +vn -0.137400 0.881000 0.452800 +vn -0.137400 -0.881000 0.452800 +vn -0.224800 -0.632600 0.741200 +vn -0.451300 -0.289000 0.844300 +vn -0.469100 0.097600 0.877700 +vn -0.416200 0.469600 0.778600 +vn -0.299900 0.771500 0.561100 +vn -0.137400 -0.956500 0.257100 +vn -0.137400 0.956500 0.257100 +vn -0.299900 -0.771500 0.561100 +vn -0.416200 -0.469600 0.778600 +vn -0.469100 -0.097600 0.877700 +vn -0.451300 0.289000 0.844300 +vn -0.365100 0.632600 0.683100 +vn -0.223100 0.881000 0.417300 +vn -0.223100 -0.881000 0.417300 +vn -0.365100 -0.632600 0.683100 +vn -0.607300 -0.289000 0.740000 +vn -0.631400 0.097600 0.769300 +vn -0.560100 0.469600 0.682500 +vn -0.403600 0.771500 0.491800 +vn -0.185000 -0.956500 0.225400 +vn -0.185000 0.956500 0.225400 +vn -0.403600 -0.771500 0.491800 +vn -0.560100 -0.469600 0.682500 +vn -0.631400 -0.097600 0.769300 +vn -0.607300 0.289000 0.740000 +vn -0.491300 0.632600 0.598700 +vn -0.300200 0.881000 0.365800 +vn -0.300200 -0.881000 0.365800 +vn -0.491300 -0.632600 0.598700 +vn -0.740000 -0.289000 0.607300 +vn -0.769300 0.097600 0.631400 +vn -0.682500 0.469600 0.560100 +vn -0.491800 0.771500 0.403600 +vn -0.225400 -0.956500 0.185000 +vn -0.225400 0.956500 0.185000 +vn -0.491800 -0.771500 0.403600 +vn -0.682500 -0.469600 0.560100 +vn -0.769300 -0.097600 0.631400 +vn -0.740000 0.289000 0.607300 +vn -0.598700 0.632600 0.491300 +vn -0.365800 0.881000 0.300200 +vn -0.365800 -0.881000 0.300200 +vn -0.598700 -0.632600 0.491300 +vn -0.844300 -0.289000 0.451300 +vn -0.877700 0.097600 0.469100 +vn -0.778600 0.469600 0.416200 +vn -0.561100 0.771500 0.299900 +vn -0.257100 -0.956500 0.137400 +vn -0.257100 0.956500 0.137400 +vn -0.561100 -0.771500 0.299900 +vn -0.778600 -0.469600 0.416200 +vn -0.877700 -0.097600 0.469100 +vn -0.844300 0.289000 0.451300 +vn -0.683100 0.632600 0.365100 +vn -0.417300 0.881000 0.223000 +vn -0.417300 -0.881000 0.223000 +vn -0.683100 -0.632600 0.365100 +vn -0.916100 -0.289000 0.277900 +vn -0.952400 0.097600 0.288900 +vn -0.844800 0.469600 0.256300 +vn -0.608800 0.771500 0.184700 +vn -0.279000 -0.956500 0.084600 +vn -0.279000 0.956500 0.084600 +vn -0.608800 -0.771500 0.184700 +vn -0.844800 -0.469600 0.256300 +vn -0.952400 -0.097600 0.288900 +vn -0.916100 0.289000 0.277900 +vn -0.741200 0.632600 0.224800 +vn -0.452800 0.881000 0.137400 +vn -0.452800 -0.881000 0.137400 +vn -0.741200 -0.632600 0.224800 +vn -0.098000 -0.995100 -0.009700 +vn -0.098000 0.995100 -0.009700 +vn -0.094200 -0.995100 -0.028600 +vn -0.094200 0.995100 -0.028600 +vn -0.086900 -0.995100 -0.046400 +vn -0.086900 0.995100 -0.046400 +vn -0.076100 -0.995100 -0.062500 +vn -0.076100 0.995100 -0.062500 +vn -0.062500 -0.995100 -0.076100 +vn -0.062500 0.995100 -0.076100 +vn -0.046400 -0.995100 -0.086900 +vn -0.046400 0.995100 -0.086900 +vn -0.028600 -0.995100 -0.094200 +vn -0.028600 0.995100 -0.094200 +vn -0.009700 -0.995100 -0.098000 +vn -0.009700 0.995100 -0.098000 +vn 0.009700 -0.995100 -0.098000 +vn 0.009700 0.995100 -0.098000 +vn 0.028600 -0.995100 -0.094200 +vn 0.028600 0.995100 -0.094200 +vn 0.046400 -0.995100 -0.086900 +vn 0.046400 0.995100 -0.086900 +vn 0.062500 -0.995100 -0.076100 +vn 0.062500 0.995100 -0.076100 +vn 0.076100 -0.995100 -0.062500 +vn 0.076100 0.995100 -0.062500 +vn 0.086900 -0.995100 -0.046400 +vn 0.086900 0.995100 -0.046400 +vn 0.094200 -0.995100 -0.028600 +vn 0.094200 0.995100 -0.028600 +vn 0.098000 -0.995100 -0.009700 +vn 0.098000 0.995100 -0.009700 +vn 0.098000 -0.995100 0.009700 +vn 0.098000 0.995100 0.009700 +vn 0.094200 -0.995100 0.028600 +vn 0.094200 0.995100 0.028600 +vn 0.086900 -0.995100 0.046400 +vn 0.086900 0.995100 0.046400 +vn 0.076100 -0.995100 0.062500 +vn 0.076100 0.995100 0.062500 +vn 0.062500 -0.995100 0.076100 +vn 0.062500 0.995100 0.076100 +vn 0.046400 -0.995100 0.086900 +vn 0.046400 0.995100 0.086900 +vn 0.028600 -0.995100 0.094200 +vn 0.028600 0.995100 0.094200 +vn 0.009700 -0.995100 0.098000 +vn 0.009700 0.995100 0.098000 +vn -0.009700 -0.995100 0.098000 +vn -0.009700 0.995100 0.098000 +vn -0.028600 -0.995100 0.094200 +vn -0.028600 0.995100 0.094200 +vn -0.046400 -0.995100 0.086900 +vn -0.046400 0.995100 0.086900 +vn -0.062500 -0.995100 0.076100 +vn -0.062500 0.995100 0.076100 +vn -0.076100 -0.995100 0.062500 +vn -0.076100 0.995100 0.062500 +vn -0.086900 -0.995100 0.046400 +vn -0.086900 0.995100 0.046400 +vn -0.094200 -0.995100 0.028600 +vn -0.094200 0.995100 0.028600 +vn -0.952700 -0.289000 0.093800 +vn -0.990400 0.097500 0.097600 +vn -0.878600 0.469600 0.086500 +vn -0.633200 0.771500 0.062400 +vn -0.290200 -0.956500 0.028600 +vn -0.290200 0.956500 0.028600 +vn -0.633200 -0.771500 0.062400 +vn -0.878600 -0.469600 0.086500 +vn -0.990400 -0.097500 0.097600 +vn -0.952700 0.289000 0.093800 +vn -0.770800 0.632600 0.075900 +vn -0.098000 -0.995100 0.009700 +vn -0.470900 0.881000 0.046400 +vn -0.470900 -0.881000 0.046400 +vn -0.098000 0.995100 0.009700 +vn -0.770800 -0.632600 0.075900 +s off +f 4/1/1 3/2/1 19/3/1 20/4/1 +f 15/5/2 14/6/2 30/7/2 31/8/2 +f 2/9/3 1/10/3 17/11/3 18/12/3 +f 13/13/4 12/14/4 28/15/4 29/16/4 +f 11/17/5 10/18/5 26/19/5 27/20/5 +f 9/21/6 8/22/6 24/23/6 25/24/6 +f 7/25/7 6/26/7 22/27/7 23/28/7 +f 5/29/8 4/1/8 20/4/8 21/30/8 +f 3/2/9 2/31/9 18/32/9 19/3/9 +f 14/33/10 13/13/10 29/16/10 30/34/10 +f 12/14/11 11/17/11 27/20/11 28/15/11 +f 10/18/12 9/21/12 25/24/12 26/19/12 +f 8/22/13 7/25/13 23/28/13 24/23/13 +f 6/26/14 5/29/14 21/30/14 22/27/14 +f 26/19/15 25/24/15 40/35/15 41/36/15 +f 24/23/16 23/28/16 38/37/16 39/38/16 +f 22/27/17 21/30/17 36/39/17 37/40/17 +f 20/4/18 19/3/18 34/41/18 35/42/18 +f 31/8/19 30/7/19 45/43/19 46/44/19 +f 18/12/20 17/11/20 32/45/20 33/46/20 +f 29/16/21 28/15/21 43/47/21 44/48/21 +f 27/20/22 26/19/22 41/36/22 42/49/22 +f 25/24/23 24/23/23 39/38/23 40/35/23 +f 23/28/24 22/27/24 37/40/24 38/37/24 +f 21/30/25 20/4/25 35/42/25 36/39/25 +f 19/3/26 18/32/26 33/50/26 34/41/26 +f 30/34/27 29/16/27 44/48/27 45/51/27 +f 28/15/28 27/20/28 42/49/28 43/47/28 +f 41/36/29 40/35/29 55/52/29 56/53/29 +f 39/38/30 38/37/30 53/54/30 54/55/30 +f 37/40/31 36/39/31 51/56/31 52/57/31 +f 35/42/32 34/41/32 49/58/32 50/59/32 +f 46/44/33 45/43/33 60/60/33 61/61/33 +f 33/46/34 32/45/34 47/62/34 48/63/34 +f 44/48/35 43/47/35 58/64/35 59/65/35 +f 42/49/36 41/36/36 56/53/36 57/66/36 +f 40/35/37 39/38/37 54/55/37 55/52/37 +f 38/37/38 37/40/38 52/57/38 53/54/38 +f 36/39/39 35/42/39 50/59/39 51/56/39 +f 34/41/40 33/50/40 48/67/40 49/58/40 +f 45/51/41 44/48/41 59/65/41 60/68/41 +f 43/47/42 42/49/42 57/66/42 58/64/42 +f 56/53/43 55/52/43 70/69/43 71/70/43 +f 54/55/44 53/54/44 68/71/44 69/72/44 +f 52/57/45 51/56/45 66/73/45 67/74/45 +f 50/59/46 49/58/46 64/75/46 65/76/46 +f 61/61/47 60/60/47 75/77/47 76/78/47 +f 48/63/48 47/62/48 62/79/48 63/80/48 +f 59/65/49 58/64/49 73/81/49 74/82/49 +f 57/66/50 56/53/50 71/70/50 72/83/50 +f 55/52/51 54/55/51 69/72/51 70/69/51 +f 53/54/52 52/57/52 67/74/52 68/71/52 +f 51/56/53 50/59/53 65/76/53 66/73/53 +f 49/58/54 48/67/54 63/84/54 64/75/54 +f 60/68/55 59/65/55 74/82/55 75/85/55 +f 58/64/56 57/66/56 72/83/56 73/81/56 +f 71/70/57 70/69/57 85/86/57 86/87/57 +f 69/72/58 68/71/58 83/88/58 84/89/58 +f 67/74/59 66/73/59 81/90/59 82/91/59 +f 65/76/60 64/75/60 79/92/60 80/93/60 +f 76/78/61 75/77/61 90/94/61 91/95/61 +f 63/80/62 62/79/62 77/96/62 78/97/62 +f 74/82/63 73/81/63 88/98/63 89/99/63 +f 72/83/64 71/70/64 86/87/64 87/100/64 +f 70/69/65 69/72/65 84/89/65 85/86/65 +f 68/71/66 67/74/66 82/91/66 83/88/66 +f 66/73/67 65/76/67 80/93/67 81/90/67 +f 64/75/68 63/84/68 78/101/68 79/92/68 +f 75/85/69 74/82/69 89/99/69 90/102/69 +f 73/81/70 72/83/70 87/100/70 88/98/70 +f 86/87/71 85/86/71 100/103/71 101/104/71 +f 84/89/72 83/88/72 98/105/72 99/106/72 +f 82/91/73 81/90/73 96/107/73 97/108/73 +f 80/93/74 79/92/74 94/109/74 95/110/74 +f 91/95/75 90/94/75 105/111/75 106/112/75 +f 78/97/76 77/96/76 92/113/76 93/114/76 +f 89/99/77 88/98/77 103/115/77 104/116/77 +f 87/100/78 86/87/78 101/104/78 102/117/78 +f 85/86/79 84/89/79 99/106/79 100/103/79 +f 83/88/80 82/91/80 97/108/80 98/105/80 +f 81/90/81 80/93/81 95/110/81 96/107/81 +f 79/92/82 78/101/82 93/118/82 94/109/82 +f 90/102/83 89/99/83 104/116/83 105/119/83 +f 88/98/84 87/100/84 102/117/84 103/115/84 +f 101/104/85 100/103/85 115/120/85 116/121/85 +f 99/106/86 98/105/86 113/122/86 114/123/86 +f 97/108/87 96/107/87 111/124/87 112/125/87 +f 95/110/88 94/109/88 109/126/88 110/127/88 +f 106/112/89 105/111/89 120/128/89 121/129/89 +f 93/114/90 92/113/90 107/130/90 108/131/90 +f 104/116/91 103/115/91 118/132/91 119/133/91 +f 102/117/92 101/104/92 116/121/92 117/134/92 +f 100/103/93 99/106/93 114/123/93 115/120/93 +f 98/105/94 97/108/94 112/125/94 113/122/94 +f 96/107/95 95/110/95 110/127/95 111/124/95 +f 94/109/96 93/118/96 108/135/96 109/126/96 +f 105/119/97 104/116/97 119/133/97 120/136/97 +f 103/115/98 102/117/98 117/134/98 118/132/98 +f 116/121/99 115/120/99 130/137/99 131/138/99 +f 114/123/100 113/122/100 128/139/100 129/140/100 +f 112/125/101 111/124/101 126/141/101 127/142/101 +f 110/127/102 109/126/102 124/143/102 125/144/102 +f 121/129/103 120/128/103 135/145/103 136/146/103 +f 108/131/104 107/130/104 122/147/104 123/148/104 +f 119/133/105 118/132/105 133/149/105 134/150/105 +f 117/134/106 116/121/106 131/138/106 132/151/106 +f 115/120/107 114/123/107 129/140/107 130/137/107 +f 113/122/108 112/125/108 127/142/108 128/139/108 +f 111/124/109 110/127/109 125/144/109 126/141/109 +f 109/126/110 108/135/110 123/152/110 124/143/110 +f 120/136/111 119/133/111 134/150/111 135/153/111 +f 118/132/112 117/134/112 132/151/112 133/149/112 +f 131/154/113 130/155/113 145/156/113 146/157/113 +f 129/158/114 128/159/114 143/160/114 144/161/114 +f 127/162/115 126/163/115 141/164/115 142/165/115 +f 125/166/116 124/167/116 139/168/116 140/169/116 +f 136/146/117 135/145/117 150/170/117 151/171/117 +f 123/148/118 122/147/118 137/172/118 138/173/118 +f 134/174/119 133/175/119 148/176/119 149/177/119 +f 132/178/120 131/154/120 146/157/120 147/179/120 +f 130/155/121 129/158/121 144/161/121 145/156/121 +f 128/159/122 127/162/122 142/165/122 143/160/122 +f 126/163/123 125/166/123 140/169/123 141/164/123 +f 124/167/124 123/180/124 138/181/124 139/168/124 +f 135/182/125 134/174/125 149/177/125 150/183/125 +f 133/175/126 132/178/126 147/179/126 148/176/126 +f 146/157/127 145/156/127 160/184/127 161/185/127 +f 144/161/128 143/160/128 158/186/128 159/187/128 +f 142/165/129 141/164/129 156/188/129 157/189/129 +f 140/169/130 139/168/130 154/190/130 155/191/130 +f 151/171/131 150/170/131 165/192/131 166/193/131 +f 138/173/132 137/172/132 152/194/132 153/195/132 +f 149/177/133 148/176/133 163/196/133 164/197/133 +f 147/179/134 146/157/134 161/185/134 162/198/134 +f 145/156/135 144/161/135 159/187/135 160/184/135 +f 143/160/136 142/165/136 157/189/136 158/186/136 +f 141/164/137 140/169/137 155/191/137 156/188/137 +f 139/168/138 138/181/138 153/199/138 154/190/138 +f 150/183/139 149/177/139 164/197/139 165/200/139 +f 148/176/140 147/179/140 162/198/140 163/196/140 +f 161/185/141 160/184/141 175/201/141 176/202/141 +f 159/187/142 158/186/142 173/203/142 174/204/142 +f 157/189/143 156/188/143 171/205/143 172/206/143 +f 155/191/144 154/190/144 169/207/144 170/208/144 +f 166/193/145 165/192/145 180/209/145 181/210/145 +f 153/195/146 152/194/146 167/211/146 168/212/146 +f 164/197/147 163/196/147 178/213/147 179/214/147 +f 162/198/148 161/185/148 176/202/148 177/215/148 +f 160/184/149 159/187/149 174/204/149 175/201/149 +f 158/186/150 157/189/150 172/206/150 173/203/150 +f 156/188/151 155/191/151 170/208/151 171/205/151 +f 154/190/152 153/199/152 168/216/152 169/207/152 +f 165/200/153 164/197/153 179/214/153 180/217/153 +f 163/196/154 162/198/154 177/215/154 178/213/154 +f 176/202/155 175/201/155 190/218/155 191/219/155 +f 174/204/156 173/203/156 188/220/156 189/221/156 +f 172/206/157 171/205/157 186/222/157 187/223/157 +f 170/208/158 169/207/158 184/224/158 185/225/158 +f 181/210/159 180/209/159 195/226/159 196/227/159 +f 168/212/160 167/211/160 182/228/160 183/229/160 +f 179/214/161 178/213/161 193/230/161 194/231/161 +f 177/215/162 176/202/162 191/219/162 192/232/162 +f 175/201/163 174/204/163 189/221/163 190/218/163 +f 173/203/164 172/206/164 187/223/164 188/220/164 +f 171/205/165 170/208/165 185/225/165 186/222/165 +f 169/207/166 168/216/166 183/233/166 184/224/166 +f 180/217/167 179/214/167 194/231/167 195/234/167 +f 178/213/168 177/215/168 192/232/168 193/230/168 +f 191/219/169 190/218/169 205/235/169 206/236/169 +f 189/221/170 188/220/170 203/237/170 204/238/170 +f 187/223/171 186/222/171 201/239/171 202/240/171 +f 185/225/172 184/224/172 199/241/172 200/242/172 +f 196/227/173 195/226/173 210/243/173 211/244/173 +f 183/229/174 182/228/174 197/245/174 198/246/174 +f 194/231/175 193/230/175 208/247/175 209/248/175 +f 192/232/176 191/219/176 206/236/176 207/249/176 +f 190/218/177 189/221/177 204/238/177 205/235/177 +f 188/220/178 187/223/178 202/240/178 203/237/178 +f 186/222/179 185/225/179 200/242/179 201/239/179 +f 184/224/180 183/233/180 198/250/180 199/241/180 +f 195/234/181 194/231/181 209/248/181 210/251/181 +f 193/230/182 192/232/182 207/249/182 208/247/182 +f 206/236/183 205/235/183 220/252/183 221/253/183 +f 204/238/184 203/237/184 218/254/184 219/255/184 +f 202/240/185 201/239/185 216/256/185 217/257/185 +f 200/242/186 199/241/186 214/258/186 215/259/186 +f 211/244/187 210/243/187 225/260/187 226/261/187 +f 198/246/188 197/245/188 212/262/188 213/263/188 +f 209/248/189 208/247/189 223/264/189 224/265/189 +f 207/249/190 206/236/190 221/253/190 222/266/190 +f 205/235/191 204/238/191 219/255/191 220/252/191 +f 203/237/192 202/240/192 217/257/192 218/254/192 +f 201/239/193 200/242/193 215/259/193 216/256/193 +f 199/241/194 198/250/194 213/267/194 214/258/194 +f 210/251/195 209/248/195 224/265/195 225/268/195 +f 208/247/196 207/249/196 222/266/196 223/264/196 +f 221/253/197 220/252/197 235/269/197 236/270/197 +f 219/255/198 218/254/198 233/271/198 234/272/198 +f 217/257/199 216/256/199 231/273/199 232/274/199 +f 215/259/200 214/258/200 229/275/200 230/276/200 +f 226/261/201 225/260/201 240/277/201 241/278/201 +f 213/263/202 212/262/202 227/279/202 228/280/202 +f 224/265/203 223/264/203 238/281/203 239/282/203 +f 222/266/204 221/253/204 236/270/204 237/283/204 +f 220/252/205 219/255/205 234/272/205 235/269/205 +f 218/254/206 217/257/206 232/274/206 233/271/206 +f 216/256/207 215/259/207 230/276/207 231/273/207 +f 214/258/208 213/267/208 228/284/208 229/275/208 +f 225/268/209 224/265/209 239/282/209 240/285/209 +f 223/264/210 222/266/210 237/283/210 238/281/210 +f 236/270/211 235/269/211 250/286/211 251/287/211 +f 234/272/212 233/271/212 248/288/212 249/289/212 +f 232/274/213 231/273/213 246/290/213 247/291/213 +f 230/276/214 229/275/214 244/292/214 245/293/214 +f 241/278/215 240/277/215 255/294/215 256/295/215 +f 228/280/216 227/279/216 242/296/216 243/297/216 +f 239/282/217 238/281/217 253/298/217 254/299/217 +f 237/283/218 236/270/218 251/287/218 252/300/218 +f 235/269/219 234/272/219 249/289/219 250/286/219 +f 233/271/220 232/274/220 247/291/220 248/288/220 +f 231/273/221 230/276/221 245/293/221 246/290/221 +f 229/275/222 228/284/222 243/301/222 244/292/222 +f 240/285/223 239/282/223 254/299/223 255/302/223 +f 238/281/224 237/283/224 252/300/224 253/298/224 +f 251/287/225 250/286/225 265/303/225 266/304/225 +f 249/289/226 248/288/226 263/305/226 264/306/226 +f 247/291/227 246/290/227 261/307/227 262/308/227 +f 245/293/228 244/292/228 259/309/228 260/310/228 +f 256/295/229 255/294/229 270/311/229 271/312/229 +f 243/297/230 242/296/230 257/313/230 258/314/230 +f 254/299/231 253/298/231 268/315/231 269/316/231 +f 252/300/232 251/287/232 266/304/232 267/317/232 +f 250/286/233 249/289/233 264/306/233 265/303/233 +f 248/288/234 247/291/234 262/308/234 263/305/234 +f 246/290/235 245/293/235 260/310/235 261/307/235 +f 244/292/236 243/301/236 258/318/236 259/309/236 +f 255/302/237 254/299/237 269/316/237 270/319/237 +f 253/298/238 252/300/238 267/317/238 268/315/238 +f 266/304/239 265/303/239 280/320/239 281/321/239 +f 264/306/240 263/305/240 278/322/240 279/323/240 +f 262/308/241 261/307/241 276/324/241 277/325/241 +f 260/310/242 259/309/242 274/326/242 275/327/242 +f 271/312/243 270/311/243 285/328/243 286/329/243 +f 258/314/244 257/313/244 272/330/244 273/331/244 +f 269/316/245 268/315/245 283/332/245 284/333/245 +f 267/317/246 266/304/246 281/321/246 282/334/246 +f 265/303/247 264/306/247 279/323/247 280/320/247 +f 263/305/248 262/308/248 277/325/248 278/322/248 +f 261/307/249 260/310/249 275/327/249 276/324/249 +f 259/309/250 258/318/250 273/335/250 274/326/250 +f 270/319/251 269/316/251 284/333/251 285/336/251 +f 268/315/252 267/317/252 282/334/252 283/332/252 +f 281/321/253 280/320/253 295/337/253 296/338/253 +f 279/323/254 278/322/254 293/339/254 294/340/254 +f 277/325/255 276/324/255 291/341/255 292/342/255 +f 275/327/256 274/326/256 289/343/256 290/344/256 +f 286/329/257 285/328/257 300/345/257 301/346/257 +f 273/331/258 272/330/258 287/347/258 288/348/258 +f 284/333/259 283/332/259 298/349/259 299/350/259 +f 282/334/260 281/321/260 296/338/260 297/351/260 +f 280/320/261 279/323/261 294/340/261 295/337/261 +f 278/322/262 277/325/262 292/342/262 293/339/262 +f 276/324/263 275/327/263 290/344/263 291/341/263 +f 274/326/264 273/335/264 288/352/264 289/343/264 +f 285/336/265 284/333/265 299/350/265 300/353/265 +f 283/332/266 282/334/266 297/351/266 298/349/266 +f 296/338/267 295/337/267 310/354/267 311/355/267 +f 294/340/268 293/339/268 308/356/268 309/357/268 +f 292/342/269 291/341/269 306/358/269 307/359/269 +f 290/344/270 289/343/270 304/360/270 305/361/270 +f 301/346/271 300/345/271 315/362/271 316/363/271 +f 288/348/272 287/347/272 302/364/272 303/365/272 +f 299/350/273 298/349/273 313/366/273 314/367/273 +f 297/351/274 296/338/274 311/355/274 312/368/274 +f 295/337/275 294/340/275 309/357/275 310/354/275 +f 293/339/276 292/342/276 307/359/276 308/356/276 +f 291/341/277 290/344/277 305/361/277 306/358/277 +f 289/343/278 288/352/278 303/369/278 304/360/278 +f 300/353/279 299/350/279 314/367/279 315/370/279 +f 298/349/280 297/351/280 312/368/280 313/366/280 +f 311/355/281 310/354/281 325/371/281 326/372/281 +f 309/357/282 308/356/282 323/373/282 324/374/282 +f 307/359/283 306/358/283 321/375/283 322/376/283 +f 305/361/284 304/360/284 319/377/284 320/378/284 +f 316/363/285 315/362/285 330/379/285 331/380/285 +f 303/365/286 302/364/286 317/381/286 318/382/286 +f 314/367/287 313/366/287 328/383/287 329/384/287 +f 312/368/288 311/355/288 326/372/288 327/385/288 +f 310/354/289 309/357/289 324/374/289 325/371/289 +f 308/356/290 307/359/290 322/376/290 323/373/290 +f 306/358/291 305/361/291 320/378/291 321/375/291 +f 304/360/292 303/369/292 318/386/292 319/377/292 +f 315/370/293 314/367/293 329/384/293 330/387/293 +f 313/366/294 312/368/294 327/385/294 328/383/294 +f 326/372/295 325/371/295 340/388/295 341/389/295 +f 324/374/296 323/373/296 338/390/296 339/391/296 +f 322/376/297 321/375/297 336/392/297 337/393/297 +f 320/378/298 319/377/298 334/394/298 335/395/298 +f 331/380/299 330/379/299 345/396/299 346/397/299 +f 318/382/300 317/381/300 332/398/300 333/399/300 +f 329/384/301 328/383/301 343/400/301 344/401/301 +f 327/385/302 326/372/302 341/389/302 342/402/302 +f 325/371/303 324/374/303 339/391/303 340/388/303 +f 323/373/304 322/376/304 337/393/304 338/390/304 +f 321/375/305 320/378/305 335/395/305 336/392/305 +f 319/377/306 318/386/306 333/403/306 334/394/306 +f 330/387/307 329/384/307 344/401/307 345/404/307 +f 328/383/308 327/385/308 342/402/308 343/400/308 +f 341/389/309 340/388/309 355/405/309 356/406/309 +f 339/391/310 338/390/310 353/407/310 354/408/310 +f 337/393/311 336/392/311 351/409/311 352/410/311 +f 335/395/312 334/394/312 349/411/312 350/412/312 +f 346/397/313 345/396/313 360/413/313 361/414/313 +f 333/399/314 332/398/314 347/415/314 348/416/314 +f 344/401/315 343/400/315 358/417/315 359/418/315 +f 342/402/316 341/389/316 356/406/316 357/419/316 +f 340/388/317 339/391/317 354/408/317 355/405/317 +f 338/390/318 337/393/318 352/410/318 353/407/318 +f 336/392/319 335/395/319 350/412/319 351/409/319 +f 334/394/320 333/403/320 348/420/320 349/411/320 +f 345/404/321 344/401/321 359/418/321 360/421/321 +f 343/400/322 342/402/322 357/419/322 358/417/322 +f 356/406/323 355/405/323 370/422/323 371/423/323 +f 354/408/324 353/407/324 368/424/324 369/425/324 +f 352/410/325 351/409/325 366/426/325 367/427/325 +f 350/412/326 349/411/326 364/428/326 365/429/326 +f 361/414/327 360/413/327 375/430/327 376/431/327 +f 348/416/328 347/415/328 362/432/328 363/433/328 +f 359/418/329 358/417/329 373/434/329 374/435/329 +f 357/419/330 356/406/330 371/423/330 372/436/330 +f 355/405/331 354/408/331 369/425/331 370/422/331 +f 353/407/332 352/410/332 367/427/332 368/424/332 +f 351/409/333 350/412/333 365/429/333 366/426/333 +f 349/411/334 348/420/334 363/437/334 364/428/334 +f 360/421/335 359/418/335 374/435/335 375/438/335 +f 358/417/336 357/419/336 372/436/336 373/434/336 +f 371/423/337 370/422/337 385/439/337 386/440/337 +f 369/425/338 368/424/338 383/441/338 384/442/338 +f 367/427/339 366/426/339 381/443/339 382/444/339 +f 365/429/340 364/428/340 379/445/340 380/446/340 +f 376/431/341 375/430/341 390/447/341 391/448/341 +f 363/433/342 362/432/342 377/449/342 378/450/342 +f 374/435/343 373/434/343 388/451/343 389/452/343 +f 372/436/344 371/423/344 386/440/344 387/453/344 +f 370/422/345 369/425/345 384/442/345 385/439/345 +f 368/424/346 367/427/346 382/444/346 383/441/346 +f 366/426/347 365/429/347 380/446/347 381/443/347 +f 364/428/348 363/437/348 378/454/348 379/445/348 +f 375/438/349 374/435/349 389/452/349 390/455/349 +f 373/434/350 372/436/350 387/453/350 388/451/350 +f 386/440/351 385/439/351 401/456/351 402/457/351 +f 384/442/352 383/441/352 399/458/352 400/459/352 +f 382/444/353 381/443/353 397/460/353 398/461/353 +f 380/446/354 379/445/354 395/462/354 396/463/354 +f 391/448/355 390/447/355 406/464/355 407/465/355 +f 378/450/356 377/449/356 393/466/356 394/467/356 +f 389/452/357 388/451/357 404/468/357 405/469/357 +f 387/453/358 386/440/358 402/457/358 403/470/358 +f 385/439/359 384/442/359 400/459/359 401/456/359 +f 383/441/360 382/444/360 398/461/360 399/458/360 +f 381/443/361 380/446/361 396/463/361 397/460/361 +f 379/445/362 378/454/362 394/471/362 395/462/362 +f 390/455/363 389/452/363 405/469/363 406/472/363 +f 388/451/364 387/453/364 403/470/364 404/468/364 +f 402/457/365 401/456/365 416/473/365 417/474/365 +f 400/459/366 399/458/366 414/475/366 415/476/366 +f 398/461/367 397/460/367 412/477/367 413/478/367 +f 396/463/368 395/462/368 410/479/368 411/480/368 +f 407/465/369 406/464/369 421/481/369 422/482/369 +f 394/467/370 393/466/370 408/483/370 409/484/370 +f 405/469/371 404/468/371 419/485/371 420/486/371 +f 403/470/372 402/457/372 417/474/372 418/487/372 +f 401/456/373 400/459/373 415/476/373 416/473/373 +f 399/458/374 398/461/374 413/478/374 414/475/374 +f 397/460/375 396/463/375 411/480/375 412/477/375 +f 395/462/376 394/471/376 409/488/376 410/479/376 +f 406/472/377 405/469/377 420/486/377 421/489/377 +f 404/468/378 403/470/378 418/487/378 419/485/378 +f 417/474/379 416/473/379 431/490/379 432/491/379 +f 415/476/380 414/475/380 429/492/380 430/493/380 +f 413/478/381 412/477/381 427/494/381 428/495/381 +f 411/480/382 410/479/382 425/496/382 426/497/382 +f 422/482/383 421/481/383 436/498/383 437/499/383 +f 409/484/384 408/483/384 423/500/384 424/501/384 +f 420/486/385 419/485/385 434/502/385 435/503/385 +f 418/487/386 417/474/386 432/491/386 433/504/386 +f 416/473/387 415/476/387 430/493/387 431/490/387 +f 414/475/388 413/478/388 428/495/388 429/492/388 +f 412/477/389 411/480/389 426/497/389 427/494/389 +f 410/479/390 409/488/390 424/505/390 425/496/390 +f 421/489/391 420/486/391 435/503/391 436/506/391 +f 419/485/392 418/487/392 433/504/392 434/502/392 +f 432/491/393 431/490/393 446/507/393 447/508/393 +f 430/493/394 429/492/394 444/509/394 445/510/394 +f 428/495/395 427/494/395 442/511/395 443/512/395 +f 426/497/396 425/496/396 440/513/396 441/514/396 +f 437/499/397 436/498/397 451/515/397 452/516/397 +f 424/501/398 423/500/398 438/517/398 439/518/398 +f 435/503/399 434/502/399 449/519/399 450/520/399 +f 433/504/400 432/491/400 447/508/400 448/521/400 +f 431/490/401 430/493/401 445/510/401 446/507/401 +f 429/492/402 428/495/402 443/512/402 444/509/402 +f 427/494/403 426/497/403 441/514/403 442/511/403 +f 425/496/404 424/505/404 439/522/404 440/513/404 +f 436/506/405 435/503/405 450/520/405 451/523/405 +f 434/502/406 433/504/406 448/521/406 449/519/406 +f 447/508/407 446/507/407 461/524/407 462/525/407 +f 445/510/408 444/509/408 459/526/408 460/527/408 +f 443/512/409 442/511/409 457/528/409 458/529/409 +f 441/514/410 440/513/410 455/530/410 456/531/410 +f 452/516/411 451/515/411 466/532/411 467/533/411 +f 439/518/412 438/517/412 453/534/412 454/535/412 +f 450/520/413 449/519/413 464/536/413 465/537/413 +f 448/521/414 447/508/414 462/525/414 463/538/414 +f 446/507/415 445/510/415 460/527/415 461/524/415 +f 444/509/416 443/512/416 458/529/416 459/526/416 +f 442/511/417 441/514/417 456/531/417 457/528/417 +f 440/513/418 439/522/418 454/539/418 455/530/418 +f 451/523/419 450/520/419 465/537/419 466/540/419 +f 449/519/420 448/521/420 463/538/420 464/536/420 +f 462/525/421 461/524/421 476/541/421 477/542/421 +f 460/527/422 459/526/422 474/543/422 475/544/422 +f 458/529/423 457/528/423 472/545/423 473/546/423 +f 456/531/424 455/530/424 470/547/424 471/548/424 +f 467/533/425 466/532/425 481/549/425 482/550/425 +f 454/535/426 453/534/426 468/551/426 469/552/426 +f 465/537/427 464/536/427 479/553/427 480/554/427 +f 463/538/428 462/525/428 477/542/428 478/555/428 +f 461/524/429 460/527/429 475/544/429 476/541/429 +f 459/526/430 458/529/430 473/546/430 474/543/430 +f 457/528/431 456/531/431 471/548/431 472/545/431 +f 455/530/432 454/539/432 469/556/432 470/547/432 +f 466/540/433 465/537/433 480/554/433 481/557/433 +f 464/536/434 463/538/434 478/555/434 479/553/434 +f 16/558/435 15/5/435 31/8/435 +f 1/10/436 392/559/436 17/11/436 +f 16/558/437 31/8/437 46/44/437 +f 17/11/438 392/559/438 32/45/438 +f 16/558/439 46/44/439 61/61/439 +f 32/45/440 392/559/440 47/62/440 +f 16/558/441 61/61/441 76/78/441 +f 47/62/442 392/559/442 62/79/442 +f 16/558/443 76/78/443 91/95/443 +f 62/79/444 392/559/444 77/96/444 +f 16/558/445 91/95/445 106/112/445 +f 77/96/446 392/559/446 92/113/446 +f 16/558/447 106/112/447 121/129/447 +f 92/113/448 392/559/448 107/130/448 +f 16/558/449 121/129/449 136/146/449 +f 107/130/450 392/559/450 122/147/450 +f 16/558/451 136/146/451 151/171/451 +f 122/147/452 392/559/452 137/172/452 +f 16/558/453 151/171/453 166/193/453 +f 137/172/454 392/559/454 152/194/454 +f 16/558/455 166/193/455 181/210/455 +f 152/194/456 392/559/456 167/211/456 +f 16/558/457 181/210/457 196/227/457 +f 167/211/458 392/559/458 182/228/458 +f 16/558/459 196/227/459 211/244/459 +f 182/228/460 392/559/460 197/245/460 +f 16/558/461 211/244/461 226/261/461 +f 197/245/462 392/559/462 212/262/462 +f 16/558/463 226/261/463 241/278/463 +f 212/262/464 392/559/464 227/279/464 +f 16/558/465 241/278/465 256/295/465 +f 227/279/466 392/559/466 242/296/466 +f 16/558/467 256/295/467 271/312/467 +f 242/296/468 392/559/468 257/313/468 +f 16/558/469 271/312/469 286/329/469 +f 257/313/470 392/559/470 272/330/470 +f 16/558/471 286/329/471 301/346/471 +f 272/330/472 392/559/472 287/347/472 +f 16/558/473 301/346/473 316/363/473 +f 287/347/474 392/559/474 302/364/474 +f 16/558/475 316/363/475 331/380/475 +f 302/364/476 392/559/476 317/381/476 +f 16/558/477 331/380/477 346/397/477 +f 317/381/478 392/559/478 332/398/478 +f 16/558/479 346/397/479 361/414/479 +f 332/398/480 392/559/480 347/415/480 +f 16/558/481 361/414/481 376/431/481 +f 347/415/482 392/559/482 362/432/482 +f 16/558/483 376/431/483 391/448/483 +f 362/432/484 392/559/484 377/449/484 +f 16/558/485 391/448/485 407/465/485 +f 377/449/486 392/559/486 393/466/486 +f 16/558/487 407/465/487 422/482/487 +f 393/466/488 392/559/488 408/483/488 +f 16/558/489 422/482/489 437/499/489 +f 408/483/490 392/559/490 423/500/490 +f 16/558/491 437/499/491 452/516/491 +f 423/500/492 392/559/492 438/517/492 +f 16/558/493 452/516/493 467/533/493 +f 438/517/494 392/559/494 453/534/494 +f 16/558/495 467/533/495 482/550/495 +f 453/534/496 392/559/496 468/551/496 +f 477/542/497 476/541/497 9/21/497 10/18/497 +f 475/544/498 474/543/498 7/25/498 8/22/498 +f 473/546/499 472/545/499 5/29/499 6/26/499 +f 471/548/500 470/547/500 3/2/500 4/1/500 +f 482/550/501 481/549/501 14/6/501 15/5/501 +f 469/552/502 468/551/502 1/10/502 2/9/502 +f 480/554/503 479/553/503 12/14/503 13/13/503 +f 478/555/504 477/542/504 10/18/504 11/17/504 +f 476/541/505 475/544/505 8/22/505 9/21/505 +f 474/543/506 473/546/506 6/26/506 7/25/506 +f 472/545/507 471/548/507 4/1/507 5/29/507 +f 16/558/508 482/550/508 15/5/508 +f 470/547/509 469/556/509 2/31/509 3/2/509 +f 481/557/510 480/554/510 13/13/510 14/33/510 +f 468/551/511 392/559/511 1/10/511 +f 479/553/512 478/555/512 11/17/512 12/14/512 diff --git a/Geometry/clownfishBunny.png b/Levels/Geometry/clownfishBunny.png similarity index 100% rename from Geometry/clownfishBunny.png rename to Levels/Geometry/clownfishBunny.png diff --git a/Geometry/clownfishBunny.ppm b/Levels/Geometry/clownfishBunny.ppm similarity index 100% rename from Geometry/clownfishBunny.ppm rename to Levels/Geometry/clownfishBunny.ppm diff --git a/Levels/Geometry/torch.obj b/Levels/Geometry/torch.obj new file mode 100644 index 0000000..a7ce613 --- /dev/null +++ b/Levels/Geometry/torch.obj @@ -0,0 +1,266 @@ +# Blender v2.71 (sub 0) OBJ File: 'torch.blend' +# www.blender.org +o Cylinder +v 0.000000 -1.000000 -0.087051 +v -0.000000 1.000000 -0.191513 +v 0.016983 -1.000000 -0.085379 +v 0.037362 1.000000 -0.187833 +v 0.033313 -1.000000 -0.080425 +v 0.073289 1.000000 -0.176935 +v 0.048363 -1.000000 -0.072380 +v 0.106399 1.000000 -0.159237 +v 0.061555 -1.000000 -0.061555 +v 0.135420 1.000000 -0.135420 +v 0.072380 -1.000000 -0.048363 +v 0.159237 1.000000 -0.106399 +v 0.080425 -1.000000 -0.033313 +v 0.176935 1.000000 -0.073289 +v 0.085379 -1.000000 -0.016983 +v 0.187833 1.000000 -0.037362 +v 0.087051 -1.000000 -0.000000 +v 0.191513 1.000000 0.000000 +v 0.085379 -1.000000 0.016983 +v 0.187833 1.000000 0.037362 +v 0.080425 -1.000000 0.033313 +v 0.176935 1.000000 0.073289 +v 0.072380 -1.000000 0.048363 +v 0.159237 1.000000 0.106399 +v 0.061555 -1.000000 0.061555 +v 0.135420 1.000000 0.135420 +v 0.048363 -1.000000 0.072380 +v 0.106399 1.000000 0.159237 +v 0.033313 -1.000000 0.080425 +v 0.073289 1.000000 0.176935 +v 0.016983 -1.000000 0.085379 +v 0.037362 1.000000 0.187833 +v -0.000000 -1.000000 0.087051 +v -0.000000 1.000000 0.191513 +v -0.016983 -1.000000 0.085379 +v -0.037362 1.000000 0.187833 +v -0.033313 -1.000000 0.080425 +v -0.073289 1.000000 0.176935 +v -0.048363 -1.000000 0.072380 +v -0.106399 1.000000 0.159237 +v -0.061555 -1.000000 0.061555 +v -0.135420 1.000000 0.135420 +v -0.072381 -1.000000 0.048363 +v -0.159237 1.000000 0.106399 +v -0.080425 -1.000000 0.033313 +v -0.176935 1.000000 0.073289 +v -0.085379 -1.000000 0.016983 +v -0.187833 1.000000 0.037362 +v -0.087051 -1.000000 -0.000000 +v -0.191513 1.000000 -0.000000 +v -0.085379 -1.000000 -0.016983 +v -0.187833 1.000000 -0.037362 +v -0.080425 -1.000000 -0.033313 +v -0.176935 1.000000 -0.073289 +v -0.072380 -1.000000 -0.048363 +v -0.159237 1.000000 -0.106399 +v -0.061554 -1.000000 -0.061555 +v -0.135420 1.000000 -0.135420 +v -0.048363 -1.000000 -0.072381 +v -0.106399 1.000000 -0.159237 +v -0.033313 -1.000000 -0.080425 +v -0.073289 1.000000 -0.176935 +v -0.016983 -1.000000 -0.085379 +v -0.037362 1.000000 -0.187833 +vt 0.173159 0.324353 +vt 0.355490 0.133897 +vt 0.388961 0.169345 +vt 0.188374 0.340465 +vt 0.418692 0.207984 +vt 0.201889 0.358028 +vt 0.444379 0.249421 +vt 0.213565 0.376862 +vt 0.465761 0.293235 +vt 0.223285 0.396777 +vt 0.482621 0.338980 +vt 0.230950 0.417570 +vt 0.494787 0.386190 +vt 0.236481 0.439028 +vt 0.502136 0.434385 +vt 0.239822 0.460935 +vt 0.504593 0.483075 +vt 0.240940 0.483066 +vt 0.502132 0.531764 +vt 0.239822 0.505197 +vt 0.494779 0.579957 +vt 0.236481 0.527103 +vt 0.482609 0.627165 +vt 0.230950 0.548561 +vt 0.465746 0.672906 +vt 0.223286 0.569353 +vt 0.444361 0.716715 +vt 0.213567 0.589266 +vt 0.418672 0.758148 +vt 0.201891 0.608099 +vt 0.388940 0.796782 +vt 0.188377 0.625660 +vt 0.355468 0.832224 +vt 0.173163 0.641770 +vt 0.318596 0.864115 +vt 0.156403 0.656266 +vt 0.278700 0.892129 +vt 0.138269 0.669000 +vt 0.236185 0.915982 +vt 0.118944 0.679843 +vt 0.191483 0.935431 +vt 0.098625 0.688683 +vt 0.145050 0.950278 +vt 0.077519 0.695432 +vt 0.097357 0.960373 +vt 0.055840 0.700021 +vt 0.048890 0.965612 +vt 0.033810 0.702402 +vt 0.000142 0.965943 +vt 0.011651 0.702553 +vt 0.011637 0.263556 +vt 0.000142 0.000142 +vt 0.048895 0.000476 +vt 0.033797 0.263708 +vt 0.097366 0.005719 +vt 0.055829 0.266091 +vt 0.145063 0.015817 +vt 0.077509 0.270681 +vt 0.191499 0.030670 +vt 0.098617 0.277432 +vt 0.236203 0.050124 +vt 0.118937 0.286274 +vt 0.278720 0.073982 +vt 0.138263 0.297119 +vt 0.635136 0.466957 +vt 0.594601 0.439872 +vt 0.560128 0.405399 +vt 0.533043 0.364864 +vt 0.514387 0.319824 +vt 0.504876 0.272009 +vt 0.504876 0.223258 +vt 0.514387 0.175443 +vt 0.533044 0.130402 +vt 0.560129 0.089866 +vt 0.594602 0.055394 +vt 0.635137 0.028309 +vt 0.680177 0.009653 +vt 0.727992 0.000142 +vt 0.776744 0.000142 +vt 0.824559 0.009653 +vt 0.869599 0.028309 +vt 0.910135 0.055395 +vt 0.944607 0.089867 +vt 0.971691 0.130402 +vt 0.990347 0.175442 +vt 0.999858 0.223257 +vt 0.999858 0.272009 +vt 0.990347 0.319823 +vt 0.971691 0.364863 +vt 0.944606 0.405398 +vt 0.910133 0.439871 +vt 0.869598 0.466956 +vt 0.824557 0.485613 +vt 0.776743 0.495124 +vt 0.727992 0.495124 +vt 0.680177 0.485613 +vt 0.156399 0.309855 +vt 0.318618 0.102002 +vt 0.545660 0.520522 +vt 0.564085 0.508211 +vt 0.584558 0.499731 +vt 0.606292 0.495408 +vt 0.628452 0.495407 +vt 0.650186 0.499730 +vt 0.670659 0.508211 +vt 0.689084 0.520522 +vt 0.704753 0.536191 +vt 0.717065 0.554616 +vt 0.725545 0.575089 +vt 0.729868 0.596823 +vt 0.729868 0.618983 +vt 0.725545 0.640717 +vt 0.717065 0.661190 +vt 0.704754 0.679615 +vt 0.689084 0.695284 +vt 0.670659 0.707596 +vt 0.650185 0.716076 +vt 0.628452 0.720399 +vt 0.606292 0.720399 +vt 0.584558 0.716076 +vt 0.564085 0.707595 +vt 0.545660 0.695284 +vt 0.529990 0.679615 +vt 0.517679 0.661190 +vt 0.509199 0.640717 +vt 0.504876 0.618983 +vt 0.504876 0.596824 +vt 0.509199 0.575090 +vt 0.517679 0.554617 +vt 0.529991 0.536192 +vn 0.097900 -0.051900 -0.993800 +vn 0.289900 -0.051900 -0.955700 +vn 0.470800 -0.051900 -0.880700 +vn 0.633500 -0.051900 -0.772000 +vn 0.772000 -0.051900 -0.633500 +vn 0.880700 -0.051900 -0.470800 +vn 0.955700 -0.051900 -0.289900 +vn 0.993800 -0.051900 -0.097900 +vn 0.993800 -0.051900 0.097900 +vn 0.955700 -0.051900 0.289900 +vn 0.880700 -0.051900 0.470800 +vn 0.772000 -0.051900 0.633500 +vn 0.633500 -0.051900 0.772000 +vn 0.470800 -0.051900 0.880700 +vn 0.289900 -0.051900 0.955700 +vn 0.097900 -0.051900 0.993800 +vn -0.097900 -0.051900 0.993800 +vn -0.289900 -0.051900 0.955600 +vn -0.470800 -0.051900 0.880700 +vn -0.633500 -0.051900 0.772000 +vn -0.772000 -0.051900 0.633500 +vn -0.880700 -0.051900 0.470800 +vn -0.955700 -0.051900 0.289900 +vn -0.993800 -0.051900 0.097900 +vn -0.993800 -0.051900 -0.097900 +vn -0.955600 -0.051900 -0.289900 +vn -0.880700 -0.051900 -0.470800 +vn -0.772000 -0.051900 -0.633500 +vn -0.633500 -0.051900 -0.772000 +vn -0.470800 -0.051900 -0.880700 +vn 0.000000 1.000000 0.000000 +vn -0.097900 -0.051900 -0.993800 +vn -0.289900 -0.051900 -0.955700 +vn 0.000000 -1.000000 0.000000 +s off +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 3/4/2 4/3/2 6/5/2 5/6/2 +f 5/6/3 6/5/3 8/7/3 7/8/3 +f 7/8/4 8/7/4 10/9/4 9/10/4 +f 9/10/5 10/9/5 12/11/5 11/12/5 +f 11/12/6 12/11/6 14/13/6 13/14/6 +f 13/14/7 14/13/7 16/15/7 15/16/7 +f 15/16/8 16/15/8 18/17/8 17/18/8 +f 17/18/9 18/17/9 20/19/9 19/20/9 +f 19/20/10 20/19/10 22/21/10 21/22/10 +f 21/22/11 22/21/11 24/23/11 23/24/11 +f 23/24/12 24/23/12 26/25/12 25/26/12 +f 25/26/13 26/25/13 28/27/13 27/28/13 +f 27/28/14 28/27/14 30/29/14 29/30/14 +f 29/30/15 30/29/15 32/31/15 31/32/15 +f 31/32/16 32/31/16 34/33/16 33/34/16 +f 33/34/17 34/33/17 36/35/17 35/36/17 +f 35/36/18 36/35/18 38/37/18 37/38/18 +f 37/38/19 38/37/19 40/39/19 39/40/19 +f 39/40/20 40/39/20 42/41/20 41/42/20 +f 41/42/21 42/41/21 44/43/21 43/44/21 +f 43/44/22 44/43/22 46/45/22 45/46/22 +f 45/46/23 46/45/23 48/47/23 47/48/23 +f 47/48/24 48/47/24 50/49/24 49/50/24 +f 49/51/25 50/52/25 52/53/25 51/54/25 +f 51/54/26 52/53/26 54/55/26 53/56/26 +f 53/56/27 54/55/27 56/57/27 55/58/27 +f 55/58/28 56/57/28 58/59/28 57/60/28 +f 57/60/29 58/59/29 60/61/29 59/62/29 +f 59/62/30 60/61/30 62/63/30 61/64/30 +f 4/65/31 2/66/31 64/67/31 62/68/31 60/69/31 58/70/31 56/71/31 54/72/31 52/73/31 50/74/31 48/75/31 46/76/31 44/77/31 42/78/31 40/79/31 38/80/31 36/81/31 34/82/31 32/83/31 30/84/31 28/85/31 26/86/31 24/87/31 22/88/31 20/89/31 18/90/31 16/91/31 14/92/31 12/93/31 10/94/31 8/95/31 6/96/31 +f 63/97/32 64/98/32 2/2/32 1/1/32 +f 61/64/33 62/63/33 64/98/33 63/97/33 +f 1/99/34 3/100/34 5/101/34 7/102/34 9/103/34 11/104/34 13/105/34 15/106/34 17/107/34 19/108/34 21/109/34 23/110/34 25/111/34 27/112/34 29/113/34 31/114/34 33/115/34 35/116/34 37/117/34 39/118/34 41/119/34 43/120/34 45/121/34 47/122/34 49/123/34 51/124/34 53/125/34 55/126/34 57/127/34 59/128/34 61/129/34 63/130/34 diff --git a/Levels/Textures/blockTexture.png b/Levels/Textures/blockTexture.png new file mode 100644 index 0000000..0186dce Binary files /dev/null and b/Levels/Textures/blockTexture.png differ diff --git a/Levels/Textures/columnTexture.png b/Levels/Textures/columnTexture.png new file mode 100644 index 0000000..9eef9ff Binary files /dev/null and b/Levels/Textures/columnTexture.png differ diff --git a/Levels/Textures/marbleTexture.png b/Levels/Textures/marbleTexture.png new file mode 100644 index 0000000..20322d9 Binary files /dev/null and b/Levels/Textures/marbleTexture.png differ diff --git a/Levels/Textures/stoneTexture.png b/Levels/Textures/stoneTexture.png new file mode 100644 index 0000000..5bc577c Binary files /dev/null and b/Levels/Textures/stoneTexture.png differ diff --git a/Levels/Textures/terrainTexture.png b/Levels/Textures/terrainTexture.png new file mode 100644 index 0000000..42ea4de Binary files /dev/null and b/Levels/Textures/terrainTexture.png differ diff --git a/Levels/Textures/torchTexture.png b/Levels/Textures/torchTexture.png new file mode 100644 index 0000000..b86fcc9 Binary files /dev/null and b/Levels/Textures/torchTexture.png differ diff --git a/Levels/LevelTest/terrain/heightmap.png b/Levels/heightmapLvlTest.png similarity index 100% rename from Levels/LevelTest/terrain/heightmap.png rename to Levels/heightmapLvlTest.png diff --git a/Shader/phong.vsh b/Shader/phong.vsh index db75dd4..4b71ce9 100644 --- a/Shader/phong.vsh +++ b/Shader/phong.vsh @@ -4,8 +4,8 @@ uniform mat4 modelMatrix; uniform mat4 viewMatrix; uniform mat4 projectionMatrix; -in vec3 aNormal; in vec3 aPosition; +in vec3 aNormal; in vec2 aTexCoord; out vec3 vNormal; diff --git a/camera.cc b/camera.cc index 2036d94..109ff7a 100644 --- a/camera.cc +++ b/camera.cc @@ -1,12 +1,12 @@ #include "camera.hh" -Camera::Camera(glm::vec3 rotation, float distance) { +Camera::Camera(glm::vec2 rotation, float distance) { this->rotation = rotation; this->distance = distance; } Camera::Camera() { - rotation = glm::vec3(0.0f, 0.0f, 0.0f); + rotation = glm::vec2(0.0f, 0.0f); distance = 1.0f; } @@ -19,16 +19,56 @@ float Camera::getDistance() { void Camera::setDistance(float distance) { this->distance = distance; + updatePosition(); } -glm::vec3 Camera::getRotation() { +glm::vec2 Camera::getRotation() { return rotation; } -void Camera::setRotation(glm::vec3 rotation) { +void Camera::setRotation(glm::vec2 rotation) { this->rotation = rotation; + updatePosition(); } -void Camera::updateRotation(glm::vec3 rotation) { - this->rotation += rotation;; +void Camera::updateRotation(glm::vec2 rotation) { + this->rotation += rotation; + if((this->rotation.x + rotation.x) >= 1.57f) { + this->rotation.x = 1.57; + this->rotation.y += rotation.y; + } + else if ((this->rotation.x + rotation.x) <= -1.57f) { + this->rotation.x = -1.57f; + this->rotation.y += rotation.y; + } + else { + this-> rotation += rotation; + } + updatePosition(); } + +void Camera:: updateDistance(float distance) { + if (this->distance + distance <= 1.0f) { + this->distance = 1.0f; + } + else if (this->distance + distance >= 30.0f) { + this->distance = 30.f; + } + else { + this->distance += distance; + } + updatePosition(); +} + +void Camera::updatePosition() { + glm::vec4 cameraVector = glm::vec4(0.0f, 0.0f, distance, 0.0f); + // rotate vector + glm::mat4 rotationMatrix = + glm::rotate(rotation[1], glm::vec3(0.0f, 1.0f, 0.0f)) * glm::rotate(rotation[0], glm::vec3(1.0f, 0.0f, 0.0f)); + this->vector = glm::vec3(rotationMatrix * cameraVector); +} + +glm::vec3 Camera::getVector() { + return vector; +} + diff --git a/camera.hh b/camera.hh index 7cf3d98..70337cc 100644 --- a/camera.hh +++ b/camera.hh @@ -5,17 +5,21 @@ class Camera { public: - Camera(glm::vec3 rotation, float distance); + Camera(glm::vec2 rotation, float distance); Camera(); ~Camera(); float getDistance(); void setDistance(float distance); - glm::vec3 getRotation(); - void setRotation(glm::vec3 rotation); - void updateRotation(glm::vec3 rotation); //adds to current rotation + void updateDistance(float distance); //adds to current distance + glm::vec2 getRotation(); + void setRotation(glm::vec2 rotation); + void updateRotation(glm::vec2 rotation); //adds to current rotation + glm::vec3 getVector(); private: + void updatePosition(); float distance; - glm::vec3 rotation; + glm::vec2 rotation; + glm::vec3 vector; }; #endif diff --git a/entity.cc b/entity.cc index 4f68a6d..20a92d8 100644 --- a/entity.cc +++ b/entity.cc @@ -1,6 +1,11 @@ #include "entity.hh" Entity::Entity(glm::vec3 position, glm::vec3 rotation) { + this->position = position; + setRotation(rotation); +} + +Entity::Entity(glm::vec3 position, glm::mat4 rotation) { this->position = position; this->rotation = rotation; } @@ -15,7 +20,7 @@ glm::vec3 Entity::getPosition() { return position; } -glm::vec3 Entity::getRotation() { +glm::mat4 Entity::getRotation() { return rotation; } @@ -24,5 +29,11 @@ void Entity::setPosition(glm::vec3 position) { } void Entity::setRotation(glm::vec3 rotation) { + this->rotation = glm::rotate(rotation.x, glm::vec3(1.0f, 0.0f, 0.0f)) + * glm::rotate(rotation.y, glm::vec3(0.0f, 1.0f, 0.0f)) + * glm::rotate(rotation.z, glm::vec3(0.0f, 0.0f, 1.0f)); +} + +void Entity::setRotation(glm::mat4 rotation) { this->rotation = rotation; } diff --git a/entity.hh b/entity.hh index 959cf5d..c712644 100644 --- a/entity.hh +++ b/entity.hh @@ -6,15 +6,17 @@ class Entity { public: Entity(glm::vec3 position, glm::vec3 rotation); + Entity(glm::vec3 position, glm::mat4 rotation); Entity(); ~Entity(); void setPosition(glm::vec3 positon); void setRotation(glm::vec3 rotation); + void setRotation(glm::mat4 rotation); glm::vec3 getPosition(); - glm::vec3 getRotation(); + glm::mat4 getRotation(); private: glm::vec3 position; - glm::vec3 rotation; + glm::mat4 rotation; }; #endif diff --git a/extern/bullet/src/LinearMath/btAlignedObjectArray.h b/extern/bullet/src/LinearMath/btAlignedObjectArray.h index 24e59ab..ab6c41c 100644 --- a/extern/bullet/src/LinearMath/btAlignedObjectArray.h +++ b/extern/bullet/src/LinearMath/btAlignedObjectArray.h @@ -17,6 +17,8 @@ subject to the following restrictions: #ifndef BT_OBJECT_ARRAY__ #define BT_OBJECT_ARRAY__ +#pragma GCC diagnostic ignored "-Wunused-variable" + #include "btScalar.h" // has definitions like SIMD_FORCE_INLINE #include "btAlignedAllocator.h" diff --git a/graphics.cc b/graphics.cc index 4832d62..3385480 100644 --- a/graphics.cc +++ b/graphics.cc @@ -1,100 +1,148 @@ #include "graphics.hh" +#include +#include +#include +#include + +#include +#include +#include + #include "model.hh" -#include using namespace std; -ACGL::OpenGL::SharedShaderProgram shader; -Level level; - -// gets called after the OpenGL window is prepared: -void initCustomResources() -{ - // define where shaders and textures can be found: - ACGL::Base::Settings::the()->setResourcePath("../"); - ACGL::Base::Settings::the()->setShaderPath("Shader/"); - ACGL::Base::Settings::the()->setTexturePath("Geometry/"); - ACGL::Base::Settings::the()->setGeometryPath("Geometry/"); - - // load Model to give shader correct Attribute locations - // TODO look up if this is really necessary, since this looks really stupid. - Model model = Model("Bunny.obj"); - - // look up all shader files starting with 'phong' and build a ShaderProgram from it: - shader = ACGL::OpenGL::ShaderProgramCreator("phong").attributeLocations( - model.getReference()->getAttributeLocations()).create(); - shader->use(); - - // load Level - level.load(shader); - - // just in case: check for errors - openGLCriticalError(); +Graphics::Graphics() { } -void deleteCustomResources() -{ - // we have memory management via reference counting, so nothing to do here +GLFWwindow* Graphics::getWindow() { + return window; } -void draw(float runTime) -{ - // update Level first TODO: move this with the rest of the stuff that doesn't belong here to main - level.update(runTime); +glm::uvec2 Graphics::getWindowSize() { + return windowSize; +} +void Graphics::setGLFWHintsForOpenGLVersion( unsigned int _version ) +{ +#ifdef __APPLE__ +#if (ACGL_OPENGL_VERSION >= 30) + // request OpenGL 3.2, will return a 4.1 context on Mavericks + glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 ); + glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 2 ); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); +#endif +#else +// non-apple + glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, _version / 10 ); + glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, _version % 10 ); + #ifdef ACGL_OPENGL_PROFILE_CORE + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + #endif +#endif +} + +bool Graphics::createWindow() +{ + ///////////////////////////////////////////////////////////////////////////////////// + // Initialise GLFW + // + if ( !glfwInit() ) + { + ACGL::Utils::error() << "Failed to initialize GLFW" << endl; + exit( -1 ); + } + + ///////////////////////////////////////////////////////////////////////////////////// + // Configure OpenGL context + // + setGLFWHintsForOpenGLVersion( ACGL_OPENGL_VERSION ); + + // activate multisampling (second parameter is the number of samples): + //glfwWindowHint( GLFW_SAMPLES, 8 ); + + // request an OpenGL debug context: + glfwWindowHint( GLFW_OPENGL_DEBUG_CONTEXT, true ); + + // define whether the window can get resized: + glfwWindowHint(GLFW_RESIZABLE, true); + + // non-decorated windows can be used as splash screens: + //glfwWindowHint( GLFW_DECORATED, false ); + + ///////////////////////////////////////////////////////////////////////////////////// + // try to create an OpenGL context in a window and check the supported OpenGL version: + // R,G,B,A, Depth,Stencil + window = glfwCreateWindow(windowSize.x, windowSize.y, "SWP MarbleGame Group C", NULL, NULL); + if (!getWindow()) { + ACGL::Utils::error() << "Failed to open a GLFW window - requested OpenGL: " << ACGL_OPENGL_VERSION << endl; + return false; + } + glfwMakeContextCurrent(window); + ACGL::init(); + return true; +} + +Graphics::Graphics(glm::uvec2 windowSize, float nearPlane, float farPlane) { + this->windowSize = windowSize; + this->nearPlane = nearPlane; + this->farPlane = farPlane; +} + + +void Graphics::render(Level* level, ACGL::OpenGL::SharedShaderProgram shader) +{ // clear the framebuffer: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //set view and projection matrix - shader->setUniform("projectionMatrix", buildFrustum(75.0, 0.1, 100.0, (float)g_windowSize.x/(float)g_windowSize.y) ); - // the + (0,1,0) compensates bunny doesn't have its center at it's center - shader->setUniform("viewMatrix", buildViewMatrix()); + shader->setUniform("projectionMatrix", buildFrustum(75.0f, 0.1f, 100.0f, (float)windowSize.x/(float)windowSize.y) ); + shader->setUniform("viewMatrix", buildViewMatrix(level)); //set lighting parameters - if (level.getLights().size() > 0) { - shader->setUniform("lightCount", (int) level.getLights().size()); + if (level->getLights().size() > 0) { + shader->setUniform("lightCount", (int) level->getLights().size()); // TODO look into doing this less often // Build light position array - glm::vec3 lightSources[level.getLights().size()]; - for(unsigned int i = 0; igetLights().size()]; + for(unsigned int i = 0; igetLights().size(); i++) { + lightSources[i] = level->getLights()[i].getPosition(); } glUniform3fv(shader->getUniformLocation("lightSources"), sizeof(lightSources), (GLfloat*) lightSources); // Build light colour array - glm::vec3 lightColours[level.getLights().size()]; - for(unsigned int i = 0; igetLights().size()]; + for(unsigned int i = 0; igetLights().size(); i++) { + lightColours[i] = level->getLights()[i].getColour(); } glUniform3fv(shader->getUniformLocation("lightColors"), sizeof(lightColours), (GLfloat*) lightColours); // Build light attenuation array - float lightIntensities[level.getLights().size()]; - for(unsigned int i = 0; igetLights().size()]; + for(unsigned int i = 0; igetLights().size(); i++) { + lightIntensities[i] = level->getLights()[i].getIntensity(); } glUniform1fv(shader->getUniformLocation("lightIntensities"), sizeof(lightIntensities), (GLfloat*) lightIntensities); } // set Material Parameters - shader->setUniform("ambientColor", level.getAmbientLight()); + shader->setUniform("ambientColor", level->getAmbientLight()); shader->setUniform("camera", glm::vec3(0.0f, 0.0f, 0.0f)); // render the level(currently only a bunny): - level.render(); + level->render(); } -void resizeCallback( GLFWwindow *, int newWidth, int newHeight ) -{ - // store the new window size and adjust the viewport: - g_windowSize = glm::uvec2( newWidth, newHeight); - glViewport( 0, 0, g_windowSize.x, g_windowSize.y ); +void Graphics::setWindowSize(glm::uvec2 windowSize) { + this->windowSize = windowSize; } -glm::mat4 buildFrustum( float phiInDegree, float _near, float _far, float aspectRatio) { +glm::mat4 Graphics::buildFrustum( float phiInDegree, float _near, float _far, float aspectRatio) { float phiHalfInRadians = 0.5*phiInDegree * (M_PI/180.0); float top = _near * tan( phiHalfInRadians ); @@ -105,12 +153,8 @@ glm::mat4 buildFrustum( float phiInDegree, float _near, float _far, float aspect return glm::frustum(left, right, bottom, top, _near, _far); } -glm::mat4 buildViewMatrix() { - glm::vec4 cameraVector = glm::vec4(0.0f, 0.0f, level.getCamera().getDistance(), 0.0f); - // rotate vector - glm::mat4 rotationMatrix = glm::rotate(level.getCamera().getRotation()[0], glm::vec3(1.0f, 0.0f, 0.0f)) * - glm::rotate(level.getCamera().getRotation()[1], glm::vec3(0.0f, 1.0f, 0.0f)) * glm::rotate(level.getCamera().getRotation()[2], glm::vec3(0.0f, 0.0f, 1.0f)); - cameraVector = rotationMatrix * cameraVector; +glm::mat4 Graphics::buildViewMatrix(Level* level) { //construct lookAt (cameraPosition = cameraCenter + cameraVector - return glm::lookAt(level.getCameraCenter()->getPosition() + glm::vec3(cameraVector), level.getCameraCenter()->getPosition(), glm::vec3(0.0f, 1.0f, 0.0f)); + return glm::lookAt((level->getCameraCenter()->getPosition() + level->getCamera()->getVector()), + level->getCameraCenter()->getPosition(), glm::vec3(0.0f, 1.0f, 0.0f)); } diff --git a/graphics.hh b/graphics.hh index 09a3a8b..a1b451d 100644 --- a/graphics.hh +++ b/graphics.hh @@ -1,26 +1,29 @@ #ifndef GRAPHICS_HH_INCLUDED #define GRAPHICS_HH_INCLUDED +#include -#include "main.hh" - -#include +#include #include +#include "level.hh" -// gets called after the OpenGL window is prepared, init of example specific stuff: -void initCustomResources(); - -// gets called at application shutdown: -void deleteCustomResources(); - -// gets called ech frame, runTime is in seconds: -void draw(float runTime); - -// gets called at window resize: -void resizeCallback( GLFWwindow *, int newWidth, int newHeight ); - -// to build the projection matrix: -glm::mat4 buildFrustum( float phiInDegree, float near, float far, float aspectRatio); - -glm::mat4 buildViewMatrix(); +class Graphics { + public: + Graphics(glm::uvec2 windowSize, float nearPlane, float farPlane); + Graphics(); + void render(Level* level, ACGL::OpenGL::SharedShaderProgram shader); + // to build the projection matrix: + glm::mat4 buildFrustum( float phiInDegree, float near, float far, float aspectRatio); + glm::mat4 buildViewMatrix(Level* level); + glm::uvec2 getWindowSize(); + bool createWindow(); + GLFWwindow* getWindow(); + void setWindowSize(glm::uvec2 windowSize); + private: + void setGLFWHintsForOpenGLVersion( unsigned int _version ); + glm::uvec2 windowSize; + float nearPlane; + float farPlane; + GLFWwindow* window; +}; #endif diff --git a/level.cc b/level.cc index c726e08..f2d922f 100644 --- a/level.cc +++ b/level.cc @@ -1,5 +1,7 @@ #include "level.hh" + + Level::Level(std::string filePath){ this->filePath = filePath; this->terrain = Terrain(filePath + "/terrain"); @@ -12,38 +14,99 @@ Level::~Level() { } void Level::load(ACGL::OpenGL::SharedShaderProgram shader) { + + this->physics = Physics(); + this->physics.init(); + // currently hard coded should later read this stuff out of a file - this->camera = Camera(glm::vec3(-0.8f, 0.0f, 0.0f), 3.0f); + this->camera = Camera(glm::vec2(-0.8f, 0.0f), 3.0f); // load the geometry of the stanford bunny and build a VAO: - Model model = Model("Bunny.obj", 0.25f); + Model model = Model("Marble.obj", 0.75f); // load a texture: - Material material = Material("clownfishBunny.png", 0.1f, 0.5f, 0.5f, 3.0f); + Material material = Material("marbleTexture.png", 0.1f, 0.5f, 0.5f, 3.0f); //Create object - Object object = Object(model, material, glm::vec3(0.0f, -1.0f, -2.0f), + Object object = Object(model, material, glm::vec3(0.0f, 5.0f, 0.0f), + glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), + glm::vec3(0.0f, 0.0f, 0.0f), shader); + //add player to phy + this->physics.addPlayer(0.75f,0.0f,5.0f,0.0f,1.0f,0); + objects.push_back(object); + + physics.addStaticGroundPlane(); + + Model torchModel = Model("torch.obj", 0.75f); + Material torchMaterial = Material("torchTexture.png", 0.1f, 0.3f, 0.7f, 10.0f); + //Create object + Object torchObject = Object(torchModel, torchMaterial, glm::vec3(-3.0f, 5.0f, 0.0f), glm::vec3(0.0f, 1.0472f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), shader); - objects.push_back(object); - cameraCenter = &objects[0]; + objects.push_back(torchObject); + + Model blockModel = Model("Block.obj", 1.0f); + Material blockMaterial = Material("blockTexture.png", 0.1f, 0.6, 0.4f, 2.0f); + Object blockObject = Object(blockModel, blockMaterial, glm::vec3(2.0f, 5.0f, 2.0f), + glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), + shader); + objects.push_back(blockObject); + + Model columnModel = Model("Column.obj", 1.0f); + Material columnMaterial = Material("columnTexture.png", 0.1f, 0.6, 0.4f, 2.0f); + Object columnObject = Object(columnModel, columnMaterial, glm::vec3(-2.0f, 5.0f, -2.0f), + glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), + shader); + objects.push_back(columnObject); + //set lighting parameters ambientLight = glm::vec3(1.0f, 1.0f, 1.0f); - Light light = Light(glm::vec3(-3.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f), 2.0f); + Light light = Light(glm::vec3(-3.0f, 6.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f), 10.0f); lights.push_back(light); - Light light2 = Light(glm::vec3(3.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f), 2.0f); + Light light2 = Light(glm::vec3(3.0f, 6.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f), 10.0f); lights.push_back(light2); + Light light3 = Light(glm::vec3(0.0f, 5.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.5f, 0.5f, 1.0f), 4.0f); + lights.push_back(light3); + + // load terrain this->terrain.load(); + Model terrainModel = Model(this->terrain.getModel()); + // load a texture: + Material terrainMaterial = Material("terrainTexture.png", 0.1f, 0.8f, 0.2f, 3.0f); + //Create object + Object terrainObject = Object(terrainModel, terrainMaterial, + glm::vec3(-0.5f*(float)this->terrain.getHeightmapHeight(), 0.0f, -0.5f*(float)this->terrain.getHeightmapWidth()), + glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), + glm::vec3(0.0f, 0.0f, 0.0f), shader); + objects.push_back(terrainObject); + cameraCenter = &objects[0]; } void Level::render() { for(unsigned int i = 0; iterrain.render(); } -void Level::update(float runTime) { +void Level::update(float runTime, glm::vec2 mouseDelta, bool wPressed, bool aPressed, bool dPressed, bool sPressed) { // rotate bunny - cameraCenter->setRotation(glm::vec3(0.0f, 1.0472f * runTime, 0.0f)); + //cameraCenter->setRotation(glm::vec3(0.0f, 1.0472f * runTime, 0.0f)); + // Ignore first two mouse updates, because they are incorrect + static int i = 0; + if (i <2) { + i++; + } + else { + camera.updateRotation(mouseDelta/100.0f); + } + + if(wPressed) + { + //physics.rollForward(camera.getRotation); + } + + physics.takeUpdateStep(runTime); + + objects[0].setPosition(physics.getPos(0)); + lights[2].setPosition(physics.getPos(0)); } glm::vec3 Level::getAmbientLight() { @@ -54,8 +117,8 @@ std::vector Level::getLights() { return lights; } -Camera Level::getCamera() { - return camera; +Camera* Level::getCamera() { + return &camera; } Object* Level::getCameraCenter() { diff --git a/level.hh b/level.hh index e472536..db6ab73 100644 --- a/level.hh +++ b/level.hh @@ -8,6 +8,7 @@ #include "terrain.hh" #include "material.hh" #include "camera.hh" +#include "physics.hh" class Level { public: @@ -15,18 +16,19 @@ class Level { Level(); ~Level(); void load(ACGL::OpenGL::SharedShaderProgram shader); // Shader is necessary for correct texture assigning - void update(float runTime); + void update(float runTime, glm::vec2 mouseDelta,bool wPressed, bool aPressed,bool sPressed, bool dPressed); void render(); glm::vec3 getAmbientLight(); std::vector getLights(); Object* getCameraCenter(); - Camera getCamera(); + Camera* getCamera(); private: std::string filePath; std::vector objects; std::vector lights; glm::vec3 ambientLight; Object* cameraCenter; + Physics physics; Camera camera; Terrain terrain; }; diff --git a/lodepng.cpp b/lodepng.cpp new file mode 100644 index 0000000..31f146d --- /dev/null +++ b/lodepng.cpp @@ -0,0 +1,6096 @@ +/* +LodePNG version 20140823 + +Copyright (c) 2005-2014 Lode Vandevenne + +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. +*/ + +/* +The manual and changelog are in the header file "lodepng.h" +Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C. +*/ + +#include "lodepng.h" + +#include +#include + +#ifdef LODEPNG_COMPILE_CPP +#include +#endif /*LODEPNG_COMPILE_CPP*/ + +#define VERSION_STRING "20140823" + +#if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/ +#pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/ +#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ +#endif /*_MSC_VER */ + +/* +This source file is built up in the following large parts. The code sections +with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way. +-Tools for C and common code for PNG and Zlib +-C Code for Zlib (huffman, deflate, ...) +-C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...) +-The C++ wrapper around all of the above +*/ + +/*The malloc, realloc and free functions defined here with "lodepng_" in front +of the name, so that you can easily change them to others related to your +platform if needed. Everything else in the code calls these. Pass +-DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler, or comment out +#define LODEPNG_COMPILE_ALLOCATORS in the header, to disable the ones here and +define them in your own project's source files without needing to change +lodepng source code. Don't forget to remove "static" if you copypaste them +from here.*/ + +#ifdef LODEPNG_COMPILE_ALLOCATORS +static void* lodepng_malloc(size_t size) +{ + return malloc(size); +} + +static void* lodepng_realloc(void* ptr, size_t new_size) +{ + return realloc(ptr, new_size); +} + +static void lodepng_free(void* ptr) +{ + free(ptr); +} +#else /*LODEPNG_COMPILE_ALLOCATORS*/ +void* lodepng_malloc(size_t size); +void* lodepng_realloc(void* ptr, size_t new_size); +void lodepng_free(void* ptr); +#endif /*LODEPNG_COMPILE_ALLOCATORS*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // Tools for C, and common code for PNG and Zlib. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +Often in case of an error a value is assigned to a variable and then it breaks +out of a loop (to go to the cleanup phase of a function). This macro does that. +It makes the error handling code shorter and more readable. + +Example: if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83); +*/ +#define CERROR_BREAK(errorvar, code)\ +{\ + errorvar = code;\ + break;\ +} + +/*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/ +#define ERROR_BREAK(code) CERROR_BREAK(error, code) + +/*Set error var to the error code, and return it.*/ +#define CERROR_RETURN_ERROR(errorvar, code)\ +{\ + errorvar = code;\ + return code;\ +} + +/*Try the code, if it returns error, also return the error.*/ +#define CERROR_TRY_RETURN(call)\ +{\ + unsigned error = call;\ + if(error) return error;\ +} + +/* +About uivector, ucvector and string: +-All of them wrap dynamic arrays or text strings in a similar way. +-LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version. +-The string tools are made to avoid problems with compilers that declare things like strncat as deprecated. +-They're not used in the interface, only internally in this file as static functions. +-As with many other structs in this file, the init and cleanup functions serve as ctor and dtor. +*/ + +#ifdef LODEPNG_COMPILE_ZLIB +/*dynamic vector of unsigned ints*/ +typedef struct uivector +{ + unsigned* data; + size_t size; /*size in number of unsigned longs*/ + size_t allocsize; /*allocated size in bytes*/ +} uivector; + +static void uivector_cleanup(void* p) +{ + ((uivector*)p)->size = ((uivector*)p)->allocsize = 0; + lodepng_free(((uivector*)p)->data); + ((uivector*)p)->data = NULL; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_reserve(uivector* p, size_t allocsize) +{ + if(allocsize > p->allocsize) + { + size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); + void* data = lodepng_realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = (unsigned*)data; + } + else return 0; /*error: not enough memory*/ + } + return 1; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_resize(uivector* p, size_t size) +{ + if(!uivector_reserve(p, size * sizeof(unsigned))) return 0; + p->size = size; + return 1; /*success*/ +} + +/*resize and give all new elements the value*/ +static unsigned uivector_resizev(uivector* p, size_t size, unsigned value) +{ + size_t oldsize = p->size, i; + if(!uivector_resize(p, size)) return 0; + for(i = oldsize; i < size; i++) p->data[i] = value; + return 1; +} + +static void uivector_init(uivector* p) +{ + p->data = NULL; + p->size = p->allocsize = 0; +} + +#ifdef LODEPNG_COMPILE_ENCODER +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_push_back(uivector* p, unsigned c) +{ + if(!uivector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} + +/*copy q to p, returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_copy(uivector* p, const uivector* q) +{ + size_t i; + if(!uivector_resize(p, q->size)) return 0; + for(i = 0; i < q->size; i++) p->data[i] = q->data[i]; + return 1; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* /////////////////////////////////////////////////////////////////////////// */ + +/*dynamic vector of unsigned chars*/ +typedef struct ucvector +{ + unsigned char* data; + size_t size; /*used size*/ + size_t allocsize; /*allocated size*/ +} ucvector; + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_reserve(ucvector* p, size_t allocsize) +{ + if(allocsize > p->allocsize) + { + size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); + void* data = lodepng_realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = (unsigned char*)data; + } + else return 0; /*error: not enough memory*/ + } + return 1; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_resize(ucvector* p, size_t size) +{ + if(!ucvector_reserve(p, size * sizeof(unsigned char))) return 0; + p->size = size; + return 1; /*success*/ +} + +#ifdef LODEPNG_COMPILE_PNG + +static void ucvector_cleanup(void* p) +{ + ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0; + lodepng_free(((ucvector*)p)->data); + ((ucvector*)p)->data = NULL; +} + +static void ucvector_init(ucvector* p) +{ + p->data = NULL; + p->size = p->allocsize = 0; +} + +#ifdef LODEPNG_COMPILE_DECODER +/*resize and give all new elements the value*/ +static unsigned ucvector_resizev(ucvector* p, size_t size, unsigned char value) +{ + size_t oldsize = p->size, i; + if(!ucvector_resize(p, size)) return 0; + for(i = oldsize; i < size; i++) p->data[i] = value; + return 1; +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ZLIB +/*you can both convert from vector to buffer&size and vica versa. If you use +init_buffer to take over a buffer and size, it is not needed to use cleanup*/ +static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size) +{ + p->data = buffer; + p->allocsize = p->size = size; +} +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#if (defined(LODEPNG_COMPILE_PNG) && defined(LODEPNG_COMPILE_ANCILLARY_CHUNKS)) || defined(LODEPNG_COMPILE_ENCODER) +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_push_back(ucvector* p, unsigned char c) +{ + if(!ucvector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ + + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned string_resize(char** out, size_t size) +{ + char* data = (char*)lodepng_realloc(*out, size + 1); + if(data) + { + data[size] = 0; /*null termination char*/ + *out = data; + } + return data != 0; +} + +/*init a {char*, size_t} pair for use as string*/ +static void string_init(char** out) +{ + *out = NULL; + string_resize(out, 0); +} + +/*free the above pair again*/ +static void string_cleanup(char** out) +{ + lodepng_free(*out); + *out = NULL; +} + +static void string_set(char** out, const char* in) +{ + size_t insize = strlen(in), i = 0; + if(string_resize(out, insize)) + { + for(i = 0; i < insize; i++) + { + (*out)[i] = in[i]; + } + } +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned lodepng_read32bitInt(const unsigned char* buffer) +{ + return (unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]); +} + +#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER) +/*buffer must have at least 4 allocated bytes available*/ +static void lodepng_set32bitInt(unsigned char* buffer, unsigned value) +{ + buffer[0] = (unsigned char)((value >> 24) & 0xff); + buffer[1] = (unsigned char)((value >> 16) & 0xff); + buffer[2] = (unsigned char)((value >> 8) & 0xff); + buffer[3] = (unsigned char)((value ) & 0xff); +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ + +#ifdef LODEPNG_COMPILE_ENCODER +static void lodepng_add32bitInt(ucvector* buffer, unsigned value) +{ + ucvector_resize(buffer, buffer->size + 4); /*todo: give error if resize failed*/ + lodepng_set32bitInt(&buffer->data[buffer->size - 4], value); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / File IO / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DISK + +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) +{ + FILE* file; + long size; + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + + file = fopen(filename, "rb"); + if(!file) return 78; + + /*get filesize:*/ + fseek(file , 0 , SEEK_END); + size = ftell(file); + rewind(file); + + /*read contents of the file into the vector*/ + *outsize = 0; + *out = (unsigned char*)lodepng_malloc((size_t)size); + if(size && (*out)) (*outsize) = fread(*out, 1, (size_t)size, file); + + fclose(file); + if(!(*out) && size) return 83; /*the above malloc failed*/ + return 0; +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename) +{ + FILE* file; + file = fopen(filename, "wb" ); + if(!file) return 79; + fwrite((char*)buffer , 1 , buffersize, file); + fclose(file); + return 0; +} + +#endif /*LODEPNG_COMPILE_DISK*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of common code and tools. Begin of Zlib related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_ENCODER +/*TODO: this ignores potential out of memory errors*/ +#define addBitToStream(/*size_t**/ bitpointer, /*ucvector**/ bitstream, /*unsigned char*/ bit)\ +{\ + /*add a new byte at the end*/\ + if(((*bitpointer) & 7) == 0) ucvector_push_back(bitstream, (unsigned char)0);\ + /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/\ + (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7));\ + (*bitpointer)++;\ +} + +static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) +{ + size_t i; + for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1)); +} + +static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) +{ + size_t i; + for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1)); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +#define READBIT(bitpointer, bitstream) ((bitstream[bitpointer >> 3] >> (bitpointer & 0x7)) & (unsigned char)1) + +static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream) +{ + unsigned char result = (unsigned char)(READBIT(*bitpointer, bitstream)); + (*bitpointer)++; + return result; +} + +static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) +{ + unsigned result = 0, i; + for(i = 0; i < nbits; i++) + { + result += ((unsigned)READBIT(*bitpointer, bitstream)) << i; + (*bitpointer)++; + } + return result; +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflate - Huffman / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#define FIRST_LENGTH_CODE_INDEX 257 +#define LAST_LENGTH_CODE_INDEX 285 +/*256 literals, the end code, some length codes, and 2 unused codes*/ +#define NUM_DEFLATE_CODE_SYMBOLS 288 +/*the distance codes have their own symbols, 30 used, 2 unused*/ +#define NUM_DISTANCE_SYMBOLS 32 +/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/ +#define NUM_CODE_LENGTH_CODES 19 + +/*the base lengths represented by codes 257-285*/ +static const unsigned LENGTHBASE[29] + = {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}; + +/*the extra bits used by codes 257-285 (added to base length)*/ +static const unsigned LENGTHEXTRA[29] + = {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}; + +/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/ +static const unsigned DISTANCEBASE[30] + = {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}; + +/*the extra bits of backwards distances (added to base)*/ +static const unsigned DISTANCEEXTRA[30] + = {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}; + +/*the order in which "code length alphabet code lengths" are stored, out of this +the huffman tree of the dynamic huffman tree lengths is generated*/ +static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES] + = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +Huffman tree struct, containing multiple representations of the tree +*/ +typedef struct HuffmanTree +{ + unsigned* tree2d; + unsigned* tree1d; + unsigned* lengths; /*the lengths of the codes of the 1d-tree*/ + unsigned maxbitlen; /*maximum number of bits a single code can get*/ + unsigned numcodes; /*number of symbols in the alphabet = number of codes*/ +} HuffmanTree; + +/*function used for debug purposes to draw the tree in ascii art with C++*/ +/* +static void HuffmanTree_draw(HuffmanTree* tree) +{ + std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl; + for(size_t i = 0; i < tree->tree1d.size; i++) + { + if(tree->lengths.data[i]) + std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl; + } + std::cout << std::endl; +}*/ + +static void HuffmanTree_init(HuffmanTree* tree) +{ + tree->tree2d = 0; + tree->tree1d = 0; + tree->lengths = 0; +} + +static void HuffmanTree_cleanup(HuffmanTree* tree) +{ + lodepng_free(tree->tree2d); + lodepng_free(tree->tree1d); + lodepng_free(tree->lengths); +} + +/*the tree representation used by the decoder. return value is error*/ +static unsigned HuffmanTree_make2DTree(HuffmanTree* tree) +{ + unsigned nodefilled = 0; /*up to which node it is filled*/ + unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/ + unsigned n, i; + + tree->tree2d = (unsigned*)lodepng_malloc(tree->numcodes * 2 * sizeof(unsigned)); + if(!tree->tree2d) return 83; /*alloc fail*/ + + /* + convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means + uninited, a value >= numcodes is an address to another bit, a value < numcodes + is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as + many columns as codes - 1. + A good huffmann tree has N * 2 - 1 nodes, of which N - 1 are internal nodes. + Here, the internal nodes are stored (what their 0 and 1 option point to). + There is only memory for such good tree currently, if there are more nodes + (due to too long length codes), error 55 will happen + */ + for(n = 0; n < tree->numcodes * 2; n++) + { + tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/ + } + + for(n = 0; n < tree->numcodes; n++) /*the codes*/ + { + for(i = 0; i < tree->lengths[n]; i++) /*the bits for this code*/ + { + unsigned char bit = (unsigned char)((tree->tree1d[n] >> (tree->lengths[n] - i - 1)) & 1); + if(treepos > tree->numcodes - 2) return 55; /*oversubscribed, see comment in lodepng_error_text*/ + if(tree->tree2d[2 * treepos + bit] == 32767) /*not yet filled in*/ + { + if(i + 1 == tree->lengths[n]) /*last bit*/ + { + tree->tree2d[2 * treepos + bit] = n; /*put the current code in it*/ + treepos = 0; + } + else + { + /*put address of the next step in here, first that address has to be found of course + (it's just nodefilled + 1)...*/ + nodefilled++; + /*addresses encoded with numcodes added to it*/ + tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes; + treepos = nodefilled; + } + } + else treepos = tree->tree2d[2 * treepos + bit] - tree->numcodes; + } + } + + for(n = 0; n < tree->numcodes * 2; n++) + { + if(tree->tree2d[n] == 32767) tree->tree2d[n] = 0; /*remove possible remaining 32767's*/ + } + + return 0; +} + +/* +Second step for the ...makeFromLengths and ...makeFromFrequencies functions. +numcodes, lengths and maxbitlen must already be filled in correctly. return +value is error. +*/ +static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) +{ + uivector blcount; + uivector nextcode; + unsigned bits, n, error = 0; + + uivector_init(&blcount); + uivector_init(&nextcode); + + tree->tree1d = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned)); + if(!tree->tree1d) error = 83; /*alloc fail*/ + + if(!uivector_resizev(&blcount, tree->maxbitlen + 1, 0) + || !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0)) + error = 83; /*alloc fail*/ + + if(!error) + { + /*step 1: count number of instances of each code length*/ + for(bits = 0; bits < tree->numcodes; bits++) blcount.data[tree->lengths[bits]]++; + /*step 2: generate the nextcode values*/ + for(bits = 1; bits <= tree->maxbitlen; bits++) + { + nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1; + } + /*step 3: generate all the codes*/ + for(n = 0; n < tree->numcodes; n++) + { + if(tree->lengths[n] != 0) tree->tree1d[n] = nextcode.data[tree->lengths[n]]++; + } + } + + uivector_cleanup(&blcount); + uivector_cleanup(&nextcode); + + if(!error) return HuffmanTree_make2DTree(tree); + else return error; +} + +/* +given the code lengths (as stored in the PNG file), generate the tree as defined +by Deflate. maxbitlen is the maximum bits that a code in the tree can have. +return value is error. +*/ +static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen, + size_t numcodes, unsigned maxbitlen) +{ + unsigned i; + tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + for(i = 0; i < numcodes; i++) tree->lengths[i] = bitlen[i]; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->maxbitlen = maxbitlen; + return HuffmanTree_makeFromLengths2(tree); +} + +#ifdef LODEPNG_COMPILE_ENCODER + +/* +A coin, this is the terminology used for the package-merge algorithm and the +coin collector's problem. This is used to generate the huffman tree. +A coin can be multiple coins (when they're merged) +*/ +typedef struct Coin +{ + uivector symbols; + float weight; /*the sum of all weights in this coin*/ +} Coin; + +static void coin_init(Coin* c) +{ + uivector_init(&c->symbols); +} + +/*argument c is void* so that this dtor can be given as function pointer to the vector resize function*/ +static void coin_cleanup(void* c) +{ + uivector_cleanup(&((Coin*)c)->symbols); +} + +static void coin_copy(Coin* c1, const Coin* c2) +{ + c1->weight = c2->weight; + uivector_copy(&c1->symbols, &c2->symbols); +} + +static void add_coins(Coin* c1, const Coin* c2) +{ + size_t i; + for(i = 0; i < c2->symbols.size; i++) uivector_push_back(&c1->symbols, c2->symbols.data[i]); + c1->weight += c2->weight; +} + +static void init_coins(Coin* coins, size_t num) +{ + size_t i; + for(i = 0; i < num; i++) coin_init(&coins[i]); +} + +static void cleanup_coins(Coin* coins, size_t num) +{ + size_t i; + for(i = 0; i < num; i++) coin_cleanup(&coins[i]); +} + +static int coin_compare(const void* a, const void* b) { + float wa = ((const Coin*)a)->weight; + float wb = ((const Coin*)b)->weight; + return wa > wb ? 1 : wa < wb ? -1 : 0; +} + +static unsigned append_symbol_coins(Coin* coins, const unsigned* frequencies, unsigned numcodes, size_t sum) +{ + unsigned i; + unsigned j = 0; /*index of present symbols*/ + for(i = 0; i < numcodes; i++) + { + if(frequencies[i] != 0) /*only include symbols that are present*/ + { + coins[j].weight = frequencies[i] / (float)sum; + uivector_push_back(&coins[j].symbols, i); + j++; + } + } + return 0; +} + +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen) +{ + unsigned i, j; + size_t sum = 0, numpresent = 0; + unsigned error = 0; + Coin* coins; /*the coins of the currently calculated row*/ + Coin* prev_row; /*the previous row of coins*/ + size_t numcoins; + size_t coinmem; + + if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/ + + for(i = 0; i < numcodes; i++) + { + if(frequencies[i] > 0) + { + numpresent++; + sum += frequencies[i]; + } + } + + for(i = 0; i < numcodes; i++) lengths[i] = 0; + + /*ensure at least two present symbols. There should be at least one symbol + according to RFC 1951 section 3.2.7. To decoders incorrectly require two. To + make these work as well ensure there are at least two symbols. The + Package-Merge code below also doesn't work correctly if there's only one + symbol, it'd give it the theoritical 0 bits but in practice zlib wants 1 bit*/ + if(numpresent == 0) + { + lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/ + } + else if(numpresent == 1) + { + for(i = 0; i < numcodes; i++) + { + if(frequencies[i]) + { + lengths[i] = 1; + lengths[i == 0 ? 1 : 0] = 1; + break; + } + } + } + else + { + /*Package-Merge algorithm represented by coin collector's problem + For every symbol, maxbitlen coins will be created*/ + + coinmem = numpresent * 2; /*max amount of coins needed with the current algo*/ + coins = (Coin*)lodepng_malloc(sizeof(Coin) * coinmem); + prev_row = (Coin*)lodepng_malloc(sizeof(Coin) * coinmem); + if(!coins || !prev_row) + { + lodepng_free(coins); + lodepng_free(prev_row); + return 83; /*alloc fail*/ + } + init_coins(coins, coinmem); + init_coins(prev_row, coinmem); + + /*first row, lowest denominator*/ + error = append_symbol_coins(coins, frequencies, numcodes, sum); + numcoins = numpresent; + qsort(coins, numcoins, sizeof(Coin), coin_compare); + if(!error) + { + unsigned numprev = 0; + for(j = 1; j <= maxbitlen && !error; j++) /*each of the remaining rows*/ + { + unsigned tempnum; + Coin* tempcoins; + /*swap prev_row and coins, and their amounts*/ + tempcoins = prev_row; prev_row = coins; coins = tempcoins; + tempnum = numprev; numprev = numcoins; numcoins = tempnum; + + cleanup_coins(coins, numcoins); + init_coins(coins, numcoins); + + numcoins = 0; + + /*fill in the merged coins of the previous row*/ + for(i = 0; i + 1 < numprev; i += 2) + { + /*merge prev_row[i] and prev_row[i + 1] into new coin*/ + Coin* coin = &coins[numcoins++]; + coin_copy(coin, &prev_row[i]); + add_coins(coin, &prev_row[i + 1]); + } + /*fill in all the original symbols again*/ + if(j < maxbitlen) + { + error = append_symbol_coins(coins + numcoins, frequencies, numcodes, sum); + numcoins += numpresent; + } + qsort(coins, numcoins, sizeof(Coin), coin_compare); + } + } + + if(!error) + { + /*calculate the lenghts of each symbol, as the amount of times a coin of each symbol is used*/ + for(i = 0; i < numpresent - 1; i++) + { + Coin* coin = &coins[i]; + for(j = 0; j < coin->symbols.size; j++) lengths[coin->symbols.data[j]]++; + } + } + + cleanup_coins(coins, coinmem); + lodepng_free(coins); + cleanup_coins(prev_row, coinmem); + lodepng_free(prev_row); + } + + return error; +} + +/*Create the Huffman tree given the symbol frequencies*/ +static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies, + size_t mincodes, size_t numcodes, unsigned maxbitlen) +{ + unsigned error = 0; + while(!frequencies[numcodes - 1] && numcodes > mincodes) numcodes--; /*trim zeroes*/ + tree->maxbitlen = maxbitlen; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->lengths = (unsigned*)lodepng_realloc(tree->lengths, numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + /*initialize all lengths to 0*/ + memset(tree->lengths, 0, numcodes * sizeof(unsigned)); + + error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen); + if(!error) error = HuffmanTree_makeFromLengths2(tree); + return error; +} + +static unsigned HuffmanTree_getCode(const HuffmanTree* tree, unsigned index) +{ + return tree->tree1d[index]; +} + +static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index) +{ + return tree->lengths[index]; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/ +static unsigned generateFixedLitLenTree(HuffmanTree* tree) +{ + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/ + for(i = 0; i <= 143; i++) bitlen[i] = 8; + for(i = 144; i <= 255; i++) bitlen[i] = 9; + for(i = 256; i <= 279; i++) bitlen[i] = 7; + for(i = 280; i <= 287; i++) bitlen[i] = 8; + + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15); + + lodepng_free(bitlen); + return error; +} + +/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static unsigned generateFixedDistanceTree(HuffmanTree* tree) +{ + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*there are 32 distance codes, but 30-31 are unused*/ + for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen[i] = 5; + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15); + + lodepng_free(bitlen); + return error; +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* +returns the code, or (unsigned)(-1) if error happened +inbitlength is the length of the complete buffer, in bits (so its byte length times 8) +*/ +static unsigned huffmanDecodeSymbol(const unsigned char* in, size_t* bp, + const HuffmanTree* codetree, size_t inbitlength) +{ + unsigned treepos = 0, ct; + for(;;) + { + if(*bp >= inbitlength) return (unsigned)(-1); /*error: end of input memory reached without endcode*/ + /* + decode the symbol from the tree. The "readBitFromStream" code is inlined in + the expression below because this is the biggest bottleneck while decoding + */ + ct = codetree->tree2d[(treepos << 1) + READBIT(*bp, in)]; + (*bp)++; + if(ct < codetree->numcodes) return ct; /*the symbol is decoded, return it*/ + else treepos = ct - codetree->numcodes; /*symbol not yet decoded, instead move tree position*/ + + if(treepos >= codetree->numcodes) return (unsigned)(-1); /*error: it appeared outside the codetree*/ + } +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Inflator (Decompressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static void getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d) +{ + /*TODO: check for out of memory errors*/ + generateFixedLitLenTree(tree_ll); + generateFixedDistanceTree(tree_d); +} + +/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/ +static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, + const unsigned char* in, size_t* bp, size_t inlength) +{ + /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/ + unsigned error = 0; + unsigned n, HLIT, HDIST, HCLEN, i; + size_t inbitlength = inlength * 8; + + /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/ + unsigned* bitlen_ll = 0; /*lit,len code lengths*/ + unsigned* bitlen_d = 0; /*dist code lengths*/ + /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/ + unsigned* bitlen_cl = 0; + HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/ + + if((*bp) >> 3 >= inlength - 2) return 49; /*error: the bit pointer is or will go past the memory*/ + + /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ + HLIT = readBitsFromStream(bp, in, 5) + 257; + /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/ + HDIST = readBitsFromStream(bp, in, 5) + 1; + /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/ + HCLEN = readBitsFromStream(bp, in, 4) + 4; + + HuffmanTree_init(&tree_cl); + + while(!error) + { + /*read the code length codes out of 3 * (amount of code length codes) bits*/ + + bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned)); + if(!bitlen_cl) ERROR_BREAK(83 /*alloc fail*/); + + for(i = 0; i < NUM_CODE_LENGTH_CODES; i++) + { + if(i < HCLEN) bitlen_cl[CLCL_ORDER[i]] = readBitsFromStream(bp, in, 3); + else bitlen_cl[CLCL_ORDER[i]] = 0; /*if not, it must stay 0*/ + } + + error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7); + if(error) break; + + /*now we can use this tree to read the lengths for the tree that this function will return*/ + bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i < NUM_DEFLATE_CODE_SYMBOLS; i++) bitlen_ll[i] = 0; + for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen_d[i] = 0; + + /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/ + i = 0; + while(i < HLIT + HDIST) + { + unsigned code = huffmanDecodeSymbol(in, bp, &tree_cl, inbitlength); + if(code <= 15) /*a length code*/ + { + if(i < HLIT) bitlen_ll[i] = code; + else bitlen_d[i - HLIT] = code; + i++; + } + else if(code == 16) /*repeat previous*/ + { + unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/ + unsigned value; /*set value to the previous code*/ + + if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + if (i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/ + + replength += readBitsFromStream(bp, in, 2); + + if(i < HLIT + 1) value = bitlen_ll[i - 1]; + else value = bitlen_d[i - HLIT - 1]; + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; n++) + { + if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/ + if(i < HLIT) bitlen_ll[i] = value; + else bitlen_d[i - HLIT] = value; + i++; + } + } + else if(code == 17) /*repeat "0" 3-10 times*/ + { + unsigned replength = 3; /*read in the bits that indicate repeat length*/ + if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + + replength += readBitsFromStream(bp, in, 3); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; n++) + { + if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + i++; + } + } + else if(code == 18) /*repeat "0" 11-138 times*/ + { + unsigned replength = 11; /*read in the bits that indicate repeat length*/ + if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + + replength += readBitsFromStream(bp, in, 7); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; n++) + { + if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + i++; + } + } + else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + if(code == (unsigned)(-1)) + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inbitlength ? 10 : 11; + } + else error = 16; /*unexisting code, this can never happen*/ + break; + } + } + if(error) break; + + if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/ + + /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/ + error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15); + if(error) break; + error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15); + + break; /*end of error-while*/ + } + + lodepng_free(bitlen_cl); + lodepng_free(bitlen_ll); + lodepng_free(bitlen_d); + HuffmanTree_cleanup(&tree_cl); + + return error; +} + +/*inflate a block with dynamic of fixed Huffman tree*/ +static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp, + size_t* pos, size_t inlength, unsigned btype) +{ + unsigned error = 0; + HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ + HuffmanTree tree_d; /*the huffman tree for distance codes*/ + size_t inbitlength = inlength * 8; + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + if(btype == 1) getTreeInflateFixed(&tree_ll, &tree_d); + else if(btype == 2) error = getTreeInflateDynamic(&tree_ll, &tree_d, in, bp, inlength); + + while(!error) /*decode all symbols until end reached, breaks at end code*/ + { + /*code_ll is literal, length or end code*/ + unsigned code_ll = huffmanDecodeSymbol(in, bp, &tree_ll, inbitlength); + if(code_ll <= 255) /*literal symbol*/ + { + /*ucvector_push_back would do the same, but for some reason the two lines below run 10% faster*/ + if(!ucvector_resize(out, (*pos) + 1)) ERROR_BREAK(83 /*alloc fail*/); + out->data[*pos] = (unsigned char)code_ll; + (*pos)++; + } + else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ + { + unsigned code_d, distance; + unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/ + size_t start, forward, backward, length; + + /*part 1: get length base*/ + length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX]; + + /*part 2: get extra bits and add the value of that to length*/ + numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX]; + if(*bp >= inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ + length += readBitsFromStream(bp, in, numextrabits_l); + + /*part 3: get distance code*/ + code_d = huffmanDecodeSymbol(in, bp, &tree_d, inbitlength); + if(code_d > 29) + { + if(code_ll == (unsigned)(-1)) /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inlength * 8 ? 10 : 11; + } + else error = 18; /*error: invalid distance code (30-31 are never used)*/ + break; + } + distance = DISTANCEBASE[code_d]; + + /*part 4: get extra bits from distance*/ + numextrabits_d = DISTANCEEXTRA[code_d]; + if(*bp >= inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ + + distance += readBitsFromStream(bp, in, numextrabits_d); + + /*part 5: fill in all the out[n] values based on the length and dist*/ + start = (*pos); + if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ + backward = start - distance; + + if(!ucvector_resize(out, (*pos) + length)) ERROR_BREAK(83 /*alloc fail*/); + for(forward = 0; forward < length; forward++) + { + out->data[(*pos)] = out->data[backward]; + (*pos)++; + backward++; + if(backward >= start) backward = start - distance; + } + } + else if(code_ll == 256) + { + break; /*end code, break the loop*/ + } + else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inlength * 8 ? 10 : 11; + break; + } + } + + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned inflateNoCompression(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength) +{ + /*go to first boundary of byte*/ + size_t p; + unsigned LEN, NLEN, n, error = 0; + while(((*bp) & 0x7) != 0) (*bp)++; + p = (*bp) / 8; /*byte position*/ + + /*read LEN (2 bytes) and NLEN (2 bytes)*/ + if(p >= inlength - 4) return 52; /*error, bit pointer will jump past memory*/ + LEN = in[p] + 256u * in[p + 1]; p += 2; + NLEN = in[p] + 256u * in[p + 1]; p += 2; + + /*check if 16-bit NLEN is really the one's complement of LEN*/ + if(LEN + NLEN != 65535) return 21; /*error: NLEN is not one's complement of LEN*/ + + if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/ + + /*read the literal data: LEN bytes are now stored in the out buffer*/ + if(p + LEN > inlength) return 23; /*error: reading outside of in buffer*/ + for(n = 0; n < LEN; n++) out->data[(*pos)++] = in[p++]; + + (*bp) = p * 8; + + return error; +} + +static unsigned lodepng_inflatev(ucvector* out, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte)*/ + size_t bp = 0; + unsigned BFINAL = 0; + size_t pos = 0; /*byte position in the out buffer*/ + unsigned error = 0; + + (void)settings; + + while(!BFINAL) + { + unsigned BTYPE; + if(bp + 2 >= insize * 8) return 52; /*error, bit pointer will jump past memory*/ + BFINAL = readBitFromStream(&bp, in); + BTYPE = 1u * readBitFromStream(&bp, in); + BTYPE += 2u * readBitFromStream(&bp, in); + + if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ + else if(BTYPE == 0) error = inflateNoCompression(out, in, &bp, &pos, insize); /*no compression*/ + else error = inflateHuffmanBlock(out, in, &bp, &pos, insize, BTYPE); /*compression, BTYPE 01 or 10*/ + + if(error) return error; + } + + return error; +} + +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + unsigned error; + ucvector v; + ucvector_init_buffer(&v, *out, *outsize); + error = lodepng_inflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + if(settings->custom_inflate) + { + return settings->custom_inflate(out, outsize, in, insize, settings); + } + else + { + return lodepng_inflate(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflator (Compressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258; + +/*bitlen is the size in bits of the code*/ +static void addHuffmanSymbol(size_t* bp, ucvector* compressed, unsigned code, unsigned bitlen) +{ + addBitsToStreamReversed(bp, compressed, code, bitlen); +} + +/*search the index in the array, that has the largest value smaller than or equal to the given value, +given array must be sorted (if no value is smaller, it returns the size of the given array)*/ +static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) +{ + /*linear search implementation*/ + /*for(size_t i = 1; i < array_size; i++) if(array[i] > value) return i - 1; + return array_size - 1;*/ + + /*binary search implementation (not that much faster) (precondition: array_size > 0)*/ + size_t left = 1; + size_t right = array_size - 1; + while(left <= right) + { + size_t mid = (left + right) / 2; + if(array[mid] <= value) left = mid + 1; /*the value to find is more to the right*/ + else if(array[mid - 1] > value) right = mid - 1; /*the value to find is more to the left*/ + else return mid - 1; + } + return array_size - 1; +} + +static void addLengthDistance(uivector* values, size_t length, size_t distance) +{ + /*values in encoded vector are those used by deflate: + 0-255: literal bytes + 256: end + 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits) + 286-287: invalid*/ + + unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length); + unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]); + unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance); + unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]); + + uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX); + uivector_push_back(values, extra_length); + uivector_push_back(values, dist_code); + uivector_push_back(values, extra_distance); +} + +/*3 bytes of data get encoded into two bytes. The hash cannot use more than 3 +bytes as input because 3 is the minimum match length for deflate*/ +static const unsigned HASH_NUM_VALUES = 65536; +static const unsigned HASH_BIT_MASK = 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/ + +typedef struct Hash +{ + int* head; /*hash value to head circular pos - can be outdated if went around window*/ + /*circular pos to prev circular pos*/ + unsigned short* chain; + int* val; /*circular pos to hash value*/ + + /*TODO: do this not only for zeros but for any repeated byte. However for PNG + it's always going to be the zeros that dominate, so not important for PNG*/ + int* headz; /*similar to head, but for chainz*/ + unsigned short* chainz; /*those with same amount of zeros*/ + unsigned short* zeros; /*length of zeros streak, used as a second hash chain*/ +} Hash; + +static unsigned hash_init(Hash* hash, unsigned windowsize) +{ + unsigned i; + hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES); + hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize); + hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + + hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + hash->headz = (int*)lodepng_malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1)); + hash->chainz = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + + if(!hash->head || !hash->chain || !hash->val || !hash->headz|| !hash->chainz || !hash->zeros) + { + return 83; /*alloc fail*/ + } + + /*initialize hash table*/ + for(i = 0; i < HASH_NUM_VALUES; i++) hash->head[i] = -1; + for(i = 0; i < windowsize; i++) hash->val[i] = -1; + for(i = 0; i < windowsize; i++) hash->chain[i] = i; /*same value as index indicates uninitialized*/ + + for(i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; i++) hash->headz[i] = -1; + for(i = 0; i < windowsize; i++) hash->chainz[i] = i; /*same value as index indicates uninitialized*/ + + return 0; +} + +static void hash_cleanup(Hash* hash) +{ + lodepng_free(hash->head); + lodepng_free(hash->val); + lodepng_free(hash->chain); + + lodepng_free(hash->zeros); + lodepng_free(hash->headz); + lodepng_free(hash->chainz); +} + + + +static unsigned getHash(const unsigned char* data, size_t size, size_t pos) +{ + unsigned result = 0; + if (pos + 2 < size) + { + /*A simple shift and xor hash is used. Since the data of PNGs is dominated + by zeroes due to the filters, a better hash does not have a significant + effect on speed in traversing the chain, and causes more time spend on + calculating the hash.*/ + result ^= (unsigned)(data[pos + 0] << 0u); + result ^= (unsigned)(data[pos + 1] << 4u); + result ^= (unsigned)(data[pos + 2] << 8u); + } else { + size_t amount, i; + if(pos >= size) return 0; + amount = size - pos; + for(i = 0; i < amount; i++) result ^= (unsigned)(data[pos + i] << (i * 8u)); + } + return result & HASH_BIT_MASK; +} + +static unsigned countZeros(const unsigned char* data, size_t size, size_t pos) +{ + const unsigned char* start = data + pos; + const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH; + if(end > data + size) end = data + size; + data = start; + while (data != end && *data == 0) data++; + /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/ + return (unsigned)(data - start); +} + +/*wpos = pos & (windowsize - 1)*/ +static void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros) +{ + hash->val[wpos] = (int)hashval; + if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval]; + hash->head[hashval] = wpos; + + hash->zeros[wpos] = numzeros; + if(hash->headz[numzeros] != -1) hash->chainz[wpos] = hash->headz[numzeros]; + hash->headz[numzeros] = wpos; +} + +/* +LZ77-encode the data. Return value is error code. The input are raw bytes, the output +is in the form of unsigned integers with codes representing for example literal bytes, or +length/distance pairs. +It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a +sliding window (of windowsize) is used, and all past bytes in that window can be used as +the "dictionary". A brute force search through all possible distances would be slow, and +this hash technique is one out of several ways to speed this up. +*/ +static unsigned encodeLZ77(uivector* out, Hash* hash, + const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize, + unsigned minmatch, unsigned nicematch, unsigned lazymatching) +{ + size_t pos; + unsigned i, error = 0; + /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/ + unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8; + unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; + + unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/ + unsigned numzeros = 0; + + unsigned offset; /*the offset represents the distance in LZ77 terminology*/ + unsigned length; + unsigned lazy = 0; + unsigned lazylength = 0, lazyoffset = 0; + unsigned hashval; + unsigned current_offset, current_length; + unsigned prev_offset; + const unsigned char *lastptr, *foreptr, *backptr; + unsigned hashpos; + + if(windowsize == 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ + if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/ + + if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; + + for(pos = inpos; pos < insize; pos++) + { + size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ + unsigned chainlength = 0; + + hashval = getHash(in, insize, pos); + + if(usezeros && hashval == 0) + { + if (numzeros == 0) numzeros = countZeros(in, insize, pos); + else if (pos + numzeros > insize || in[pos + numzeros - 1] != 0) numzeros--; + } + else + { + numzeros = 0; + } + + updateHashChain(hash, wpos, hashval, numzeros); + + /*the length and offset found for the current position*/ + length = 0; + offset = 0; + + hashpos = hash->chain[wpos]; + + lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; + + /*search for the longest string*/ + prev_offset = 0; + for(;;) + { + if(chainlength++ >= maxchainlength) break; + current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize; + + if(current_offset < prev_offset) break; /*stop when went completely around the circular buffer*/ + prev_offset = current_offset; + if(current_offset > 0) + { + /*test the next characters*/ + foreptr = &in[pos]; + backptr = &in[pos - current_offset]; + + /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/ + if(numzeros >= 3) + { + unsigned skip = hash->zeros[hashpos]; + if(skip > numzeros) skip = numzeros; + backptr += skip; + foreptr += skip; + } + + while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/ + { + ++backptr; + ++foreptr; + } + current_length = (unsigned)(foreptr - &in[pos]); + + if(current_length > length) + { + length = current_length; /*the longest length*/ + offset = current_offset; /*the offset that is related to this longest length*/ + /*jump out once a length of max length is found (speed gain). This also jumps + out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/ + if(current_length >= nicematch) break; + } + } + + if(hashpos == hash->chain[hashpos]) break; + + if(numzeros >= 3 && length > numzeros) { + hashpos = hash->chainz[hashpos]; + if(hash->zeros[hashpos] != numzeros) break; + } else { + hashpos = hash->chain[hashpos]; + /*outdated hash value, happens if particular value was not encountered in whole last window*/ + if(hash->val[hashpos] != (int)hashval) break; + } + } + + if(lazymatching) + { + if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH) + { + lazy = 1; + lazylength = length; + lazyoffset = offset; + continue; /*try the next byte*/ + } + if(lazy) + { + lazy = 0; + if(pos == 0) ERROR_BREAK(81); + if(length > lazylength + 1) + { + /*push the previous character as literal*/ + if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/); + } + else + { + length = lazylength; + offset = lazyoffset; + hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/ + hash->headz[numzeros] = -1; /*idem*/ + pos--; + } + } + } + if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/); + + /*encode it as length/distance pair or literal value*/ + if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ + { + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } + else if(length < minmatch || (length == 3 && offset > 4096)) + { + /*compensate for the fact that longer offsets have more extra bits, a + length of only 3 may be not worth it then*/ + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } + else + { + addLengthDistance(out, length, offset); + for(i = 1; i < length; i++) + { + pos++; + wpos = pos & (windowsize - 1); + hashval = getHash(in, insize, pos); + if(usezeros && hashval == 0) + { + if (numzeros == 0) numzeros = countZeros(in, insize, pos); + else if (pos + numzeros > insize || in[pos + numzeros - 1] != 0) numzeros--; + } + else + { + numzeros = 0; + } + updateHashChain(hash, wpos, hashval, numzeros); + } + } + } /*end of the loop through each character of input*/ + + return error; +} + +/* /////////////////////////////////////////////////////////////////////////// */ + +static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize) +{ + /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, + 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ + + size_t i, j, numdeflateblocks = (datasize + 65534) / 65535; + unsigned datapos = 0; + for(i = 0; i < numdeflateblocks; i++) + { + unsigned BFINAL, BTYPE, LEN, NLEN; + unsigned char firstbyte; + + BFINAL = (i == numdeflateblocks - 1); + BTYPE = 0; + + firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1) << 1) + ((BTYPE & 2) << 1)); + ucvector_push_back(out, firstbyte); + + LEN = 65535; + if(datasize - datapos < 65535) LEN = (unsigned)datasize - datapos; + NLEN = 65535 - LEN; + + ucvector_push_back(out, (unsigned char)(LEN % 256)); + ucvector_push_back(out, (unsigned char)(LEN / 256)); + ucvector_push_back(out, (unsigned char)(NLEN % 256)); + ucvector_push_back(out, (unsigned char)(NLEN / 256)); + + /*Decompressed data*/ + for(j = 0; j < 65535 && datapos < datasize; j++) + { + ucvector_push_back(out, data[datapos++]); + } + } + + return 0; +} + +/* +write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees. +tree_ll: the tree for lit and len codes. +tree_d: the tree for distance codes. +*/ +static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encoded, + const HuffmanTree* tree_ll, const HuffmanTree* tree_d) +{ + size_t i = 0; + for(i = 0; i < lz77_encoded->size; i++) + { + unsigned val = lz77_encoded->data[i]; + addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_ll, val), HuffmanTree_getLength(tree_ll, val)); + if(val > 256) /*for a length code, 3 more things have to be added*/ + { + unsigned length_index = val - FIRST_LENGTH_CODE_INDEX; + unsigned n_length_extra_bits = LENGTHEXTRA[length_index]; + unsigned length_extra_bits = lz77_encoded->data[++i]; + + unsigned distance_code = lz77_encoded->data[++i]; + + unsigned distance_index = distance_code; + unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index]; + unsigned distance_extra_bits = lz77_encoded->data[++i]; + + addBitsToStream(bp, out, length_extra_bits, n_length_extra_bits); + addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_d, distance_code), + HuffmanTree_getLength(tree_d, distance_code)); + addBitsToStream(bp, out, distance_extra_bits, n_distance_extra_bits); + } + } +} + +/*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/ +static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, + const unsigned char* data, size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) +{ + unsigned error = 0; + + /* + A block is compressed as follows: The PNG data is lz77 encoded, resulting in + literal bytes and length/distance pairs. This is then huffman compressed with + two huffman trees. One huffman tree is used for the lit and len values ("ll"), + another huffman tree is used for the dist values ("d"). These two trees are + stored using their code lengths, and to compress even more these code lengths + are also run-length encoded and huffman compressed. This gives a huffman tree + of code lengths "cl". The code lenghts used to describe this third tree are + the code length code lengths ("clcl"). + */ + + /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/ + uivector lz77_encoded; + HuffmanTree tree_ll; /*tree for lit,len values*/ + HuffmanTree tree_d; /*tree for distance codes*/ + HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/ + uivector frequencies_ll; /*frequency of lit,len codes*/ + uivector frequencies_d; /*frequency of dist codes*/ + uivector frequencies_cl; /*frequency of code length codes*/ + uivector bitlen_lld; /*lit,len,dist code lenghts (int bits), literally (without repeat codes).*/ + uivector bitlen_lld_e; /*bitlen_lld encoded with repeat codes (this is a rudemtary run length compression)*/ + /*bitlen_cl is the code length code lengths ("clcl"). The bit lengths of codes to represent tree_cl + (these are written as is in the file, it would be crazy to compress these using yet another huffman + tree that needs to be represented by yet another set of code lengths)*/ + uivector bitlen_cl; + size_t datasize = dataend - datapos; + + /* + Due to the huffman compression of huffman tree representations ("two levels"), there are some anologies: + bitlen_lld is to tree_cl what data is to tree_ll and tree_d. + bitlen_lld_e is to bitlen_lld what lz77_encoded is to data. + bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded. + */ + + unsigned BFINAL = final; + size_t numcodes_ll, numcodes_d, i; + unsigned HLIT, HDIST, HCLEN; + + uivector_init(&lz77_encoded); + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + HuffmanTree_init(&tree_cl); + uivector_init(&frequencies_ll); + uivector_init(&frequencies_d); + uivector_init(&frequencies_cl); + uivector_init(&bitlen_lld); + uivector_init(&bitlen_lld_e); + uivector_init(&bitlen_cl); + + /*This while loop never loops due to a break at the end, it is here to + allow breaking out of it to the cleanup phase on error conditions.*/ + while(!error) + { + if(settings->use_lz77) + { + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(error) break; + } + else + { + if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/); + for(i = datapos; i < dataend; i++) lz77_encoded.data[i] = data[i]; /*no LZ77, but still will be Huffman compressed*/ + } + + if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83 /*alloc fail*/); + if(!uivector_resizev(&frequencies_d, 30, 0)) ERROR_BREAK(83 /*alloc fail*/); + + /*Count the frequencies of lit, len and dist codes*/ + for(i = 0; i < lz77_encoded.size; i++) + { + unsigned symbol = lz77_encoded.data[i]; + frequencies_ll.data[symbol]++; + if(symbol > 256) + { + unsigned dist = lz77_encoded.data[i + 2]; + frequencies_d.data[dist]++; + i += 3; + } + } + frequencies_ll.data[256] = 1; /*there will be exactly 1 end code, at the end of the block*/ + + /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/ + error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll.data, 257, frequencies_ll.size, 15); + if(error) break; + /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/ + error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d.data, 2, frequencies_d.size, 15); + if(error) break; + + numcodes_ll = tree_ll.numcodes; if(numcodes_ll > 286) numcodes_ll = 286; + numcodes_d = tree_d.numcodes; if(numcodes_d > 30) numcodes_d = 30; + /*store the code lengths of both generated trees in bitlen_lld*/ + for(i = 0; i < numcodes_ll; i++) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_ll, (unsigned)i)); + for(i = 0; i < numcodes_d; i++) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_d, (unsigned)i)); + + /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times), + 17 (3-10 zeroes), 18 (11-138 zeroes)*/ + for(i = 0; i < (unsigned)bitlen_lld.size; i++) + { + unsigned j = 0; /*amount of repititions*/ + while(i + j + 1 < (unsigned)bitlen_lld.size && bitlen_lld.data[i + j + 1] == bitlen_lld.data[i]) j++; + + if(bitlen_lld.data[i] == 0 && j >= 2) /*repeat code for zeroes*/ + { + j++; /*include the first zero*/ + if(j <= 10) /*repeat code 17 supports max 10 zeroes*/ + { + uivector_push_back(&bitlen_lld_e, 17); + uivector_push_back(&bitlen_lld_e, j - 3); + } + else /*repeat code 18 supports max 138 zeroes*/ + { + if(j > 138) j = 138; + uivector_push_back(&bitlen_lld_e, 18); + uivector_push_back(&bitlen_lld_e, j - 11); + } + i += (j - 1); + } + else if(j >= 3) /*repeat code for value other than zero*/ + { + size_t k; + unsigned num = j / 6, rest = j % 6; + uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); + for(k = 0; k < num; k++) + { + uivector_push_back(&bitlen_lld_e, 16); + uivector_push_back(&bitlen_lld_e, 6 - 3); + } + if(rest >= 3) + { + uivector_push_back(&bitlen_lld_e, 16); + uivector_push_back(&bitlen_lld_e, rest - 3); + } + else j -= rest; + i += j; + } + else /*too short to benefit from repeat code*/ + { + uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); + } + } + + /*generate tree_cl, the huffmantree of huffmantrees*/ + + if(!uivector_resizev(&frequencies_cl, NUM_CODE_LENGTH_CODES, 0)) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i < bitlen_lld_e.size; i++) + { + frequencies_cl.data[bitlen_lld_e.data[i]]++; + /*after a repeat code come the bits that specify the number of repetitions, + those don't need to be in the frequencies_cl calculation*/ + if(bitlen_lld_e.data[i] >= 16) i++; + } + + error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl.data, + frequencies_cl.size, frequencies_cl.size, 7); + if(error) break; + + if(!uivector_resize(&bitlen_cl, tree_cl.numcodes)) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i < tree_cl.numcodes; i++) + { + /*lenghts of code length tree is in the order as specified by deflate*/ + bitlen_cl.data[i] = HuffmanTree_getLength(&tree_cl, CLCL_ORDER[i]); + } + while(bitlen_cl.data[bitlen_cl.size - 1] == 0 && bitlen_cl.size > 4) + { + /*remove zeros at the end, but minimum size must be 4*/ + if(!uivector_resize(&bitlen_cl, bitlen_cl.size - 1)) ERROR_BREAK(83 /*alloc fail*/); + } + if(error) break; + + /* + Write everything into the output + + After the BFINAL and BTYPE, the dynamic block consists out of the following: + - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN + - (HCLEN+4)*3 bits code lengths of code length alphabet + - HLIT + 257 code lenghts of lit/length alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - HDIST + 1 code lengths of distance alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - compressed data + - 256 (end code) + */ + + /*Write block type*/ + addBitToStream(bp, out, BFINAL); + addBitToStream(bp, out, 0); /*first bit of BTYPE "dynamic"*/ + addBitToStream(bp, out, 1); /*second bit of BTYPE "dynamic"*/ + + /*write the HLIT, HDIST and HCLEN values*/ + HLIT = (unsigned)(numcodes_ll - 257); + HDIST = (unsigned)(numcodes_d - 1); + HCLEN = (unsigned)bitlen_cl.size - 4; + /*trim zeroes for HCLEN. HLIT and HDIST were already trimmed at tree creation*/ + while(!bitlen_cl.data[HCLEN + 4 - 1] && HCLEN > 0) HCLEN--; + addBitsToStream(bp, out, HLIT, 5); + addBitsToStream(bp, out, HDIST, 5); + addBitsToStream(bp, out, HCLEN, 4); + + /*write the code lenghts of the code length alphabet*/ + for(i = 0; i < HCLEN + 4; i++) addBitsToStream(bp, out, bitlen_cl.data[i], 3); + + /*write the lenghts of the lit/len AND the dist alphabet*/ + for(i = 0; i < bitlen_lld_e.size; i++) + { + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_cl, bitlen_lld_e.data[i]), + HuffmanTree_getLength(&tree_cl, bitlen_lld_e.data[i])); + /*extra bits of repeat codes*/ + if(bitlen_lld_e.data[i] == 16) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 2); + else if(bitlen_lld_e.data[i] == 17) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 3); + else if(bitlen_lld_e.data[i] == 18) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 7); + } + + /*write the compressed data symbols*/ + writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); + /*error: the length of the end code 256 must be larger than 0*/ + if(HuffmanTree_getLength(&tree_ll, 256) == 0) ERROR_BREAK(64); + + /*write the end code*/ + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); + + break; /*end of error-while*/ + } + + /*cleanup*/ + uivector_cleanup(&lz77_encoded); + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + HuffmanTree_cleanup(&tree_cl); + uivector_cleanup(&frequencies_ll); + uivector_cleanup(&frequencies_d); + uivector_cleanup(&frequencies_cl); + uivector_cleanup(&bitlen_lld_e); + uivector_cleanup(&bitlen_lld); + uivector_cleanup(&bitlen_cl); + + return error; +} + +static unsigned deflateFixed(ucvector* out, size_t* bp, Hash* hash, + const unsigned char* data, + size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) +{ + HuffmanTree tree_ll; /*tree for literal values and length codes*/ + HuffmanTree tree_d; /*tree for distance codes*/ + + unsigned BFINAL = final; + unsigned error = 0; + size_t i; + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + generateFixedLitLenTree(&tree_ll); + generateFixedDistanceTree(&tree_d); + + addBitToStream(bp, out, BFINAL); + addBitToStream(bp, out, 1); /*first bit of BTYPE*/ + addBitToStream(bp, out, 0); /*second bit of BTYPE*/ + + if(settings->use_lz77) /*LZ77 encoded*/ + { + uivector lz77_encoded; + uivector_init(&lz77_encoded); + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(!error) writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); + uivector_cleanup(&lz77_encoded); + } + else /*no LZ77, but still will be Huffman compressed*/ + { + for(i = datapos; i < dataend; i++) + { + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, data[i]), HuffmanTree_getLength(&tree_ll, data[i])); + } + } + /*add END code*/ + if(!error) addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); + + /*cleanup*/ + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + unsigned error = 0; + size_t i, blocksize, numdeflateblocks; + size_t bp = 0; /*the bit pointer*/ + Hash hash; + + if(settings->btype > 2) return 61; + else if(settings->btype == 0) return deflateNoCompression(out, in, insize); + else if(settings->btype == 1) blocksize = insize; + else /*if(settings->btype == 2)*/ + { + blocksize = insize / 8 + 8; + if(blocksize < 65535) blocksize = 65535; + } + + numdeflateblocks = (insize + blocksize - 1) / blocksize; + if(numdeflateblocks == 0) numdeflateblocks = 1; + + error = hash_init(&hash, settings->windowsize); + if(error) return error; + + for(i = 0; i < numdeflateblocks && !error; i++) + { + unsigned final = (i == numdeflateblocks - 1); + size_t start = i * blocksize; + size_t end = start + blocksize; + if(end > insize) end = insize; + + if(settings->btype == 1) error = deflateFixed(out, &bp, &hash, in, start, end, settings, final); + else if(settings->btype == 2) error = deflateDynamic(out, &bp, &hash, in, start, end, settings, final); + } + + hash_cleanup(&hash); + + return error; +} + +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + unsigned error; + ucvector v; + ucvector_init_buffer(&v, *out, *outsize); + error = lodepng_deflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + if(settings->custom_deflate) + { + return settings->custom_deflate(out, outsize, in, insize, settings); + } + else + { + return lodepng_deflate(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Adler32 */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len) +{ + unsigned s1 = adler & 0xffff; + unsigned s2 = (adler >> 16) & 0xffff; + + while(len > 0) + { + /*at least 5550 sums can be done before the sums overflow, saving a lot of module divisions*/ + unsigned amount = len > 5550 ? 5550 : len; + len -= amount; + while(amount > 0) + { + s1 += (*data++); + s2 += s1; + amount--; + } + s1 %= 65521; + s2 %= 65521; + } + + return (s2 << 16) | s1; +} + +/*Return the adler32 of the bytes data[0..len-1]*/ +static unsigned adler32(const unsigned char* data, unsigned len) +{ + return update_adler32(1L, data, len); +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Zlib / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DECODER + +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + unsigned error = 0; + unsigned CM, CINFO, FDICT; + + if(insize < 2) return 53; /*error, size of zlib data too small*/ + /*read information from zlib header*/ + if((in[0] * 256 + in[1]) % 31 != 0) + { + /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/ + return 24; + } + + CM = in[0] & 15; + CINFO = (in[0] >> 4) & 15; + /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/ + FDICT = (in[1] >> 5) & 1; + /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/ + + if(CM != 8 || CINFO > 7) + { + /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/ + return 25; + } + if(FDICT != 0) + { + /*error: the specification of PNG says about the zlib stream: + "The additional flags shall not specify a preset dictionary."*/ + return 26; + } + + error = inflate(out, outsize, in + 2, insize - 2, settings); + if(error) return error; + + if(!settings->ignore_adler32) + { + unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]); + unsigned checksum = adler32(*out, (unsigned)(*outsize)); + if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/ + } + + return 0; /*no error*/ +} + +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + if(settings->custom_zlib) + { + return settings->custom_zlib(out, outsize, in, insize, settings); + } + else + { + return lodepng_zlib_decompress(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + /*initially, *out must be NULL and outsize 0, if you just give some random *out + that's pointing to a non allocated buffer, this'll crash*/ + ucvector outv; + size_t i; + unsigned error; + unsigned char* deflatedata = 0; + size_t deflatesize = 0; + + unsigned ADLER32; + /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/ + unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/ + unsigned FLEVEL = 0; + unsigned FDICT = 0; + unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64; + unsigned FCHECK = 31 - CMFFLG % 31; + CMFFLG += FCHECK; + + /*ucvector-controlled version of the output buffer, for dynamic array*/ + ucvector_init_buffer(&outv, *out, *outsize); + + ucvector_push_back(&outv, (unsigned char)(CMFFLG / 256)); + ucvector_push_back(&outv, (unsigned char)(CMFFLG % 256)); + + error = deflate(&deflatedata, &deflatesize, in, insize, settings); + + if(!error) + { + ADLER32 = adler32(in, (unsigned)insize); + for(i = 0; i < deflatesize; i++) ucvector_push_back(&outv, deflatedata[i]); + lodepng_free(deflatedata); + lodepng_add32bitInt(&outv, ADLER32); + } + + *out = outv.data; + *outsize = outv.size; + + return error; +} + +/* compress using the default or custom zlib function */ +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + if(settings->custom_zlib) + { + return settings->custom_zlib(out, outsize, in, insize, settings); + } + else + { + return lodepng_zlib_compress(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#else /*no LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DECODER +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + if (!settings->custom_zlib) return 87; /*no custom zlib function provided */ + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + if (!settings->custom_zlib) return 87; /*no custom zlib function provided */ + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/*this is a good tradeoff between speed and compression ratio*/ +#define DEFAULT_WINDOWSIZE 2048 + +void lodepng_compress_settings_init(LodePNGCompressSettings* settings) +{ + /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/ + settings->btype = 2; + settings->use_lz77 = 1; + settings->windowsize = DEFAULT_WINDOWSIZE; + settings->minmatch = 3; + settings->nicematch = 128; + settings->lazymatching = 1; + + settings->custom_zlib = 0; + settings->custom_deflate = 0; + settings->custom_context = 0; +} + +const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0}; + + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) +{ + settings->ignore_adler32 = 0; + + settings->custom_zlib = 0; + settings->custom_inflate = 0; + settings->custom_context = 0; +} + +const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0}; + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of Zlib related code. Begin of PNG related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / CRC32 / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/* CRC polynomial: 0xedb88320 */ +static unsigned lodepng_crc32_table[256] = { + 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, + 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u, + 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u, + 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u, + 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u, + 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, + 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u, + 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u, + 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u, + 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u, + 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u, + 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, + 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u, + 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u, + 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, + 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u, + 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u, + 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u, + 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u, + 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u, + 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, + 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u, + 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u, + 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u, + 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u, + 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u, + 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, + 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u, + 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u, + 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, + 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u, + 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u +}; + +/*Return the CRC of the bytes buf[0..len-1].*/ +unsigned lodepng_crc32(const unsigned char* buf, size_t len) +{ + unsigned c = 0xffffffffL; + size_t n; + + for(n = 0; n < len; n++) + { + c = lodepng_crc32_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + return c ^ 0xffffffffL; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Reading and writing single bits and bytes from/to stream for LodePNG / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) +{ + unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1); + (*bitpointer)++; + return result; +} + +static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) +{ + unsigned result = 0; + size_t i; + for(i = nbits - 1; i < nbits; i--) + { + result += (unsigned)readBitFromReversedStream(bitpointer, bitstream) << i; + } + return result; +} + +#ifdef LODEPNG_COMPILE_DECODER +static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) +{ + /*the current bit in bitstream must be 0 for this to work*/ + if(bit) + { + /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/ + bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7))); + } + (*bitpointer)++; +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) +{ + /*the current bit in bitstream may be 0 or 1 for this to work*/ + if(bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7)))); + else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7))); + (*bitpointer)++; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG chunks / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned lodepng_chunk_length(const unsigned char* chunk) +{ + return lodepng_read32bitInt(&chunk[0]); +} + +void lodepng_chunk_type(char type[5], const unsigned char* chunk) +{ + unsigned i; + for(i = 0; i < 4; i++) type[i] = (char)chunk[4 + i]; + type[4] = 0; /*null termination char*/ +} + +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type) +{ + if(strlen(type) != 4) return 0; + return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]); +} + +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk) +{ + return((chunk[4] & 32) != 0); +} + +unsigned char lodepng_chunk_private(const unsigned char* chunk) +{ + return((chunk[6] & 32) != 0); +} + +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk) +{ + return((chunk[7] & 32) != 0); +} + +unsigned char* lodepng_chunk_data(unsigned char* chunk) +{ + return &chunk[8]; +} + +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk) +{ + return &chunk[8]; +} + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk) +{ + unsigned length = lodepng_chunk_length(chunk); + unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]); + /*the CRC is taken of the data and the 4 chunk type letters, not the length*/ + unsigned checksum = lodepng_crc32(&chunk[4], length + 4); + if(CRC != checksum) return 1; + else return 0; +} + +void lodepng_chunk_generate_crc(unsigned char* chunk) +{ + unsigned length = lodepng_chunk_length(chunk); + unsigned CRC = lodepng_crc32(&chunk[4], length + 4); + lodepng_set32bitInt(chunk + 8 + length, CRC); +} + +unsigned char* lodepng_chunk_next(unsigned char* chunk) +{ + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + return &chunk[total_chunk_length]; +} + +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk) +{ + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + return &chunk[total_chunk_length]; +} + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk) +{ + unsigned i; + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + unsigned char *chunk_start, *new_buffer; + size_t new_length = (*outlength) + total_chunk_length; + if(new_length < total_chunk_length || new_length < (*outlength)) return 77; /*integer overflow happened*/ + + new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); + if(!new_buffer) return 83; /*alloc fail*/ + (*out) = new_buffer; + (*outlength) = new_length; + chunk_start = &(*out)[new_length - total_chunk_length]; + + for(i = 0; i < total_chunk_length; i++) chunk_start[i] = chunk[i]; + + return 0; +} + +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data) +{ + unsigned i; + unsigned char *chunk, *new_buffer; + size_t new_length = (*outlength) + length + 12; + if(new_length < length + 12 || new_length < (*outlength)) return 77; /*integer overflow happened*/ + new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); + if(!new_buffer) return 83; /*alloc fail*/ + (*out) = new_buffer; + (*outlength) = new_length; + chunk = &(*out)[(*outlength) - length - 12]; + + /*1: length*/ + lodepng_set32bitInt(chunk, (unsigned)length); + + /*2: chunk name (4 letters)*/ + chunk[4] = (unsigned char)type[0]; + chunk[5] = (unsigned char)type[1]; + chunk[6] = (unsigned char)type[2]; + chunk[7] = (unsigned char)type[3]; + + /*3: the data*/ + for(i = 0; i < length; i++) chunk[8 + i] = data[i]; + + /*4: CRC (of the chunkname characters and the data)*/ + lodepng_chunk_generate_crc(chunk); + + return 0; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Color types and such / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*return type is a LodePNG error code*/ +static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) /*bd = bitdepth*/ +{ + switch(colortype) + { + case 0: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/ + case 2: if(!( bd == 8 || bd == 16)) return 37; break; /*RGB*/ + case 3: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; /*palette*/ + case 4: if(!( bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/ + case 6: if(!( bd == 8 || bd == 16)) return 37; break; /*RGBA*/ + default: return 31; + } + return 0; /*allowed color type / bits combination*/ +} + +static unsigned getNumColorChannels(LodePNGColorType colortype) +{ + switch(colortype) + { + case 0: return 1; /*grey*/ + case 2: return 3; /*RGB*/ + case 3: return 1; /*palette*/ + case 4: return 2; /*grey + alpha*/ + case 6: return 4; /*RGBA*/ + } + return 0; /*unexisting color type*/ +} + +static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth) +{ + /*bits per pixel is amount of channels * bits per channel*/ + return getNumColorChannels(colortype) * bitdepth; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +void lodepng_color_mode_init(LodePNGColorMode* info) +{ + info->key_defined = 0; + info->key_r = info->key_g = info->key_b = 0; + info->colortype = LCT_RGBA; + info->bitdepth = 8; + info->palette = 0; + info->palettesize = 0; +} + +void lodepng_color_mode_cleanup(LodePNGColorMode* info) +{ + lodepng_palette_clear(info); +} + +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source) +{ + size_t i; + lodepng_color_mode_cleanup(dest); + *dest = *source; + if(source->palette) + { + dest->palette = (unsigned char*)lodepng_malloc(1024); + if(!dest->palette && source->palettesize) return 83; /*alloc fail*/ + for(i = 0; i < source->palettesize * 4; i++) dest->palette[i] = source->palette[i]; + } + return 0; +} + +static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b) +{ + size_t i; + if(a->colortype != b->colortype) return 0; + if(a->bitdepth != b->bitdepth) return 0; + if(a->key_defined != b->key_defined) return 0; + if(a->key_defined) + { + if(a->key_r != b->key_r) return 0; + if(a->key_g != b->key_g) return 0; + if(a->key_b != b->key_b) return 0; + } + if(a->palettesize != b->palettesize) return 0; + for(i = 0; i < a->palettesize * 4; i++) + { + if(a->palette[i] != b->palette[i]) return 0; + } + return 1; +} + +void lodepng_palette_clear(LodePNGColorMode* info) +{ + if(info->palette) lodepng_free(info->palette); + info->palette = 0; + info->palettesize = 0; +} + +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + unsigned char* data; + /*the same resize technique as C++ std::vectors is used, and here it's made so that for a palette with + the max of 256 colors, it'll have the exact alloc size*/ + if(!info->palette) /*allocate palette if empty*/ + { + /*room for 256 colors with 4 bytes each*/ + data = (unsigned char*)lodepng_realloc(info->palette, 1024); + if(!data) return 83; /*alloc fail*/ + else info->palette = data; + } + info->palette[4 * info->palettesize + 0] = r; + info->palette[4 * info->palettesize + 1] = g; + info->palette[4 * info->palettesize + 2] = b; + info->palette[4 * info->palettesize + 3] = a; + info->palettesize++; + return 0; +} + +unsigned lodepng_get_bpp(const LodePNGColorMode* info) +{ + /*calculate bits per pixel out of colortype and bitdepth*/ + return lodepng_get_bpp_lct(info->colortype, info->bitdepth); +} + +unsigned lodepng_get_channels(const LodePNGColorMode* info) +{ + return getNumColorChannels(info->colortype); +} + +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info) +{ + return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA; +} + +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info) +{ + return (info->colortype & 4) != 0; /*4 or 6*/ +} + +unsigned lodepng_is_palette_type(const LodePNGColorMode* info) +{ + return info->colortype == LCT_PALETTE; +} + +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info) +{ + size_t i; + for(i = 0; i < info->palettesize; i++) + { + if(info->palette[i * 4 + 3] < 255) return 1; + } + return 0; +} + +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info) +{ + return info->key_defined + || lodepng_is_alpha_type(info) + || lodepng_has_palette_alpha(info); +} + +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color) +{ + return (w * h * lodepng_get_bpp(color) + 7) / 8; +} + +size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) +{ + return (w * h * lodepng_get_bpp_lct(colortype, bitdepth) + 7) / 8; +} + + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_DECODER +/*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer*/ +static size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, const LodePNGColorMode* color) +{ + return h * ((w * lodepng_get_bpp(color) + 7) / 8); +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static void LodePNGUnknownChunks_init(LodePNGInfo* info) +{ + unsigned i; + for(i = 0; i < 3; i++) info->unknown_chunks_data[i] = 0; + for(i = 0; i < 3; i++) info->unknown_chunks_size[i] = 0; +} + +static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info) +{ + unsigned i; + for(i = 0; i < 3; i++) lodepng_free(info->unknown_chunks_data[i]); +} + +static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src) +{ + unsigned i; + + LodePNGUnknownChunks_cleanup(dest); + + for(i = 0; i < 3; i++) + { + size_t j; + dest->unknown_chunks_size[i] = src->unknown_chunks_size[i]; + dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]); + if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/ + for(j = 0; j < src->unknown_chunks_size[i]; j++) + { + dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j]; + } + } + + return 0; +} + +/******************************************************************************/ + +static void LodePNGText_init(LodePNGInfo* info) +{ + info->text_num = 0; + info->text_keys = NULL; + info->text_strings = NULL; +} + +static void LodePNGText_cleanup(LodePNGInfo* info) +{ + size_t i; + for(i = 0; i < info->text_num; i++) + { + string_cleanup(&info->text_keys[i]); + string_cleanup(&info->text_strings[i]); + } + lodepng_free(info->text_keys); + lodepng_free(info->text_strings); +} + +static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + size_t i = 0; + dest->text_keys = 0; + dest->text_strings = 0; + dest->text_num = 0; + for(i = 0; i < source->text_num; i++) + { + CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); + } + return 0; +} + +void lodepng_clear_text(LodePNGInfo* info) +{ + LodePNGText_cleanup(info); +} + +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) +{ + char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1))); + char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1))); + if(!new_keys || !new_strings) + { + lodepng_free(new_keys); + lodepng_free(new_strings); + return 83; /*alloc fail*/ + } + + info->text_num++; + info->text_keys = new_keys; + info->text_strings = new_strings; + + string_init(&info->text_keys[info->text_num - 1]); + string_set(&info->text_keys[info->text_num - 1], key); + + string_init(&info->text_strings[info->text_num - 1]); + string_set(&info->text_strings[info->text_num - 1], str); + + return 0; +} + +/******************************************************************************/ + +static void LodePNGIText_init(LodePNGInfo* info) +{ + info->itext_num = 0; + info->itext_keys = NULL; + info->itext_langtags = NULL; + info->itext_transkeys = NULL; + info->itext_strings = NULL; +} + +static void LodePNGIText_cleanup(LodePNGInfo* info) +{ + size_t i; + for(i = 0; i < info->itext_num; i++) + { + string_cleanup(&info->itext_keys[i]); + string_cleanup(&info->itext_langtags[i]); + string_cleanup(&info->itext_transkeys[i]); + string_cleanup(&info->itext_strings[i]); + } + lodepng_free(info->itext_keys); + lodepng_free(info->itext_langtags); + lodepng_free(info->itext_transkeys); + lodepng_free(info->itext_strings); +} + +static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + size_t i = 0; + dest->itext_keys = 0; + dest->itext_langtags = 0; + dest->itext_transkeys = 0; + dest->itext_strings = 0; + dest->itext_num = 0; + for(i = 0; i < source->itext_num; i++) + { + CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i], + source->itext_transkeys[i], source->itext_strings[i])); + } + return 0; +} + +void lodepng_clear_itext(LodePNGInfo* info) +{ + LodePNGIText_cleanup(info); +} + +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str) +{ + char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1))); + char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1))); + char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1))); + char** new_strings = (char**)(lodepng_realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1))); + if(!new_keys || !new_langtags || !new_transkeys || !new_strings) + { + lodepng_free(new_keys); + lodepng_free(new_langtags); + lodepng_free(new_transkeys); + lodepng_free(new_strings); + return 83; /*alloc fail*/ + } + + info->itext_num++; + info->itext_keys = new_keys; + info->itext_langtags = new_langtags; + info->itext_transkeys = new_transkeys; + info->itext_strings = new_strings; + + string_init(&info->itext_keys[info->itext_num - 1]); + string_set(&info->itext_keys[info->itext_num - 1], key); + + string_init(&info->itext_langtags[info->itext_num - 1]); + string_set(&info->itext_langtags[info->itext_num - 1], langtag); + + string_init(&info->itext_transkeys[info->itext_num - 1]); + string_set(&info->itext_transkeys[info->itext_num - 1], transkey); + + string_init(&info->itext_strings[info->itext_num - 1]); + string_set(&info->itext_strings[info->itext_num - 1], str); + + return 0; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +void lodepng_info_init(LodePNGInfo* info) +{ + lodepng_color_mode_init(&info->color); + info->interlace_method = 0; + info->compression_method = 0; + info->filter_method = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + info->background_defined = 0; + info->background_r = info->background_g = info->background_b = 0; + + LodePNGText_init(info); + LodePNGIText_init(info); + + info->time_defined = 0; + info->phys_defined = 0; + + LodePNGUnknownChunks_init(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +void lodepng_info_cleanup(LodePNGInfo* info) +{ + lodepng_color_mode_cleanup(&info->color); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + LodePNGText_cleanup(info); + LodePNGIText_cleanup(info); + + LodePNGUnknownChunks_cleanup(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + lodepng_info_cleanup(dest); + *dest = *source; + lodepng_color_mode_init(&dest->color); + CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color)); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + CERROR_TRY_RETURN(LodePNGText_copy(dest, source)); + CERROR_TRY_RETURN(LodePNGIText_copy(dest, source)); + + LodePNGUnknownChunks_init(dest); + CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source)); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + return 0; +} + +void lodepng_info_swap(LodePNGInfo* a, LodePNGInfo* b) +{ + LodePNGInfo temp = *a; + *a = *b; + *b = temp; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +/*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/ +static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) +{ + unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/ + /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/ + unsigned p = index & m; + in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/ + in = in << (bits * (m - p)); + if(p == 0) out[index * bits / 8] = in; + else out[index * bits / 8] |= in; +} + +typedef struct ColorTree ColorTree; + +/* +One node of a color tree +This is the data structure used to count the number of unique colors and to get a palette +index for a color. It's like an octree, but because the alpha channel is used too, each +node has 16 instead of 8 children. +*/ +struct ColorTree +{ + ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/ + int index; /*the payload. Only has a meaningful value if this is in the last level*/ +}; + +static void color_tree_init(ColorTree* tree) +{ + int i; + for(i = 0; i < 16; i++) tree->children[i] = 0; + tree->index = -1; +} + +static void color_tree_cleanup(ColorTree* tree) +{ + int i; + for(i = 0; i < 16; i++) + { + if(tree->children[i]) + { + color_tree_cleanup(tree->children[i]); + lodepng_free(tree->children[i]); + } + } +} + +/*returns -1 if color not present, its index otherwise*/ +static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + int bit = 0; + for(bit = 0; bit < 8; bit++) + { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) return -1; + else tree = tree->children[i]; + } + return tree ? tree->index : -1; +} + +#ifdef LODEPNG_COMPILE_ENCODER +static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + return color_tree_get(tree, r, g, b, a) >= 0; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*color is not allowed to already exist. +Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist")*/ +static void color_tree_add(ColorTree* tree, + unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index) +{ + int bit; + for(bit = 0; bit < 8; bit++) + { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) + { + tree->children[i] = (ColorTree*)lodepng_malloc(sizeof(ColorTree)); + color_tree_init(tree->children[i]); + } + tree = tree->children[i]; + } + tree->index = (int)index; +} + +/*put a pixel, given its RGBA color, into image of any color type*/ +static unsigned rgba8ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, ColorTree* tree /*for palette*/, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + if(mode->colortype == LCT_GREY) + { + unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; + if(mode->bitdepth == 8) out[i] = grey; + else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = grey; + else + { + /*take the most significant bits of grey*/ + grey = (grey >> (8 - mode->bitdepth)) & ((1 << mode->bitdepth) - 1); + addColorBits(out, i, mode->bitdepth, grey); + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + out[i * 3 + 0] = r; + out[i * 3 + 1] = g; + out[i * 3 + 2] = b; + } + else + { + out[i * 6 + 0] = out[i * 6 + 1] = r; + out[i * 6 + 2] = out[i * 6 + 3] = g; + out[i * 6 + 4] = out[i * 6 + 5] = b; + } + } + else if(mode->colortype == LCT_PALETTE) + { + int index = color_tree_get(tree, r, g, b, a); + if(index < 0) return 82; /*color not in palette*/ + if(mode->bitdepth == 8) out[i] = index; + else addColorBits(out, i, mode->bitdepth, (unsigned)index); + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; + if(mode->bitdepth == 8) + { + out[i * 2 + 0] = grey; + out[i * 2 + 1] = a; + } + else if(mode->bitdepth == 16) + { + out[i * 4 + 0] = out[i * 4 + 1] = grey; + out[i * 4 + 2] = out[i * 4 + 3] = a; + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + out[i * 4 + 0] = r; + out[i * 4 + 1] = g; + out[i * 4 + 2] = b; + out[i * 4 + 3] = a; + } + else + { + out[i * 8 + 0] = out[i * 8 + 1] = r; + out[i * 8 + 2] = out[i * 8 + 3] = g; + out[i * 8 + 4] = out[i * 8 + 5] = b; + out[i * 8 + 6] = out[i * 8 + 7] = a; + } + } + + return 0; /*no error*/ +} + +/*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/ +static void rgba16ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, + unsigned short r, unsigned short g, unsigned short b, unsigned short a) +{ + if(mode->colortype == LCT_GREY) + { + unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; + out[i * 2 + 0] = (grey >> 8) & 255; + out[i * 2 + 1] = grey & 255; + } + else if(mode->colortype == LCT_RGB) + { + out[i * 6 + 0] = (r >> 8) & 255; + out[i * 6 + 1] = r & 255; + out[i * 6 + 2] = (g >> 8) & 255; + out[i * 6 + 3] = g & 255; + out[i * 6 + 4] = (b >> 8) & 255; + out[i * 6 + 5] = b & 255; + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; + out[i * 4 + 0] = (grey >> 8) & 255; + out[i * 4 + 1] = grey & 255; + out[i * 4 + 2] = (a >> 8) & 255; + out[i * 4 + 3] = a & 255; + } + else if(mode->colortype == LCT_RGBA) + { + out[i * 8 + 0] = (r >> 8) & 255; + out[i * 8 + 1] = r & 255; + out[i * 8 + 2] = (g >> 8) & 255; + out[i * 8 + 3] = g & 255; + out[i * 8 + 4] = (b >> 8) & 255; + out[i * 8 + 5] = b & 255; + out[i * 8 + 6] = (a >> 8) & 255; + out[i * 8 + 7] = a & 255; + } +} + +/*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/ +static void getPixelColorRGBA8(unsigned char* r, unsigned char* g, + unsigned char* b, unsigned char* a, + const unsigned char* in, size_t i, + const LodePNGColorMode* mode) +{ + if(mode->colortype == LCT_GREY) + { + if(mode->bitdepth == 8) + { + *r = *g = *b = in[i]; + if(mode->key_defined && *r == mode->key_r) *a = 0; + else *a = 255; + } + else if(mode->bitdepth == 16) + { + *r = *g = *b = in[i * 2 + 0]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 255; + } + else + { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = i * mode->bitdepth; + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + *r = *g = *b = (value * 255) / highest; + if(mode->key_defined && value == mode->key_r) *a = 0; + else *a = 255; + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2]; + if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0; + else *a = 255; + } + else + { + *r = in[i * 6 + 0]; + *g = in[i * 6 + 2]; + *b = in[i * 6 + 4]; + if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 255; + } + } + else if(mode->colortype == LCT_PALETTE) + { + unsigned index; + if(mode->bitdepth == 8) index = in[i]; + else + { + size_t j = i * mode->bitdepth; + index = readBitsFromReversedStream(&j, in, mode->bitdepth); + } + + if(index >= mode->palettesize) + { + /*This is an error according to the PNG spec, but common PNG decoders make it black instead. + Done here too, slightly faster due to no error handling needed.*/ + *r = *g = *b = 0; + *a = 255; + } + else + { + *r = mode->palette[index * 4 + 0]; + *g = mode->palette[index * 4 + 1]; + *b = mode->palette[index * 4 + 2]; + *a = mode->palette[index * 4 + 3]; + } + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + if(mode->bitdepth == 8) + { + *r = *g = *b = in[i * 2 + 0]; + *a = in[i * 2 + 1]; + } + else + { + *r = *g = *b = in[i * 4 + 0]; + *a = in[i * 4 + 2]; + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + *r = in[i * 4 + 0]; + *g = in[i * 4 + 1]; + *b = in[i * 4 + 2]; + *a = in[i * 4 + 3]; + } + else + { + *r = in[i * 8 + 0]; + *g = in[i * 8 + 2]; + *b = in[i * 8 + 4]; + *a = in[i * 8 + 6]; + } + } +} + +/*Similar to getPixelColorRGBA8, but with all the for loops inside of the color +mode test cases, optimized to convert the colors much faster, when converting +to RGBA or RGB with 8 bit per cannel. buffer must be RGBA or RGB output with +enough memory, if has_alpha is true the output is RGBA. mode has the color mode +of the input buffer.*/ +static void getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, + unsigned has_alpha, const unsigned char* in, + const LodePNGColorMode* mode) +{ + unsigned num_channels = has_alpha ? 4 : 3; + size_t i; + if(mode->colortype == LCT_GREY) + { + if(mode->bitdepth == 8) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i]; + if(has_alpha) buffer[3] = mode->key_defined && in[i] == mode->key_r ? 0 : 255; + } + } + else if(mode->bitdepth == 16) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 2]; + if(has_alpha) buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255; + } + } + else + { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = 0; + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; + if(has_alpha) buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255; + } + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = in[i * 3 + 0]; + buffer[1] = in[i * 3 + 1]; + buffer[2] = in[i * 3 + 2]; + if(has_alpha) buffer[3] = mode->key_defined && buffer[0] == mode->key_r + && buffer[1]== mode->key_g && buffer[2] == mode->key_b ? 0 : 255; + } + } + else + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = in[i * 6 + 0]; + buffer[1] = in[i * 6 + 2]; + buffer[2] = in[i * 6 + 4]; + if(has_alpha) buffer[3] = mode->key_defined + && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255; + } + } + } + else if(mode->colortype == LCT_PALETTE) + { + unsigned index; + size_t j = 0; + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + if(mode->bitdepth == 8) index = in[i]; + else index = readBitsFromReversedStream(&j, in, mode->bitdepth); + + if(index >= mode->palettesize) + { + /*This is an error according to the PNG spec, but most PNG decoders make it black instead. + Done here too, slightly faster due to no error handling needed.*/ + buffer[0] = buffer[1] = buffer[2] = 0; + if(has_alpha) buffer[3] = 255; + } + else + { + buffer[0] = mode->palette[index * 4 + 0]; + buffer[1] = mode->palette[index * 4 + 1]; + buffer[2] = mode->palette[index * 4 + 2]; + if(has_alpha) buffer[3] = mode->palette[index * 4 + 3]; + } + } + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + if(mode->bitdepth == 8) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; + if(has_alpha) buffer[3] = in[i * 2 + 1]; + } + } + else + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; + if(has_alpha) buffer[3] = in[i * 4 + 2]; + } + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = in[i * 4 + 0]; + buffer[1] = in[i * 4 + 1]; + buffer[2] = in[i * 4 + 2]; + if(has_alpha) buffer[3] = in[i * 4 + 3]; + } + } + else + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = in[i * 8 + 0]; + buffer[1] = in[i * 8 + 2]; + buffer[2] = in[i * 8 + 4]; + if(has_alpha) buffer[3] = in[i * 8 + 6]; + } + } + } +} + +/*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with +given color type, but the given color type must be 16-bit itself.*/ +static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, + const unsigned char* in, size_t i, const LodePNGColorMode* mode) +{ + if(mode->colortype == LCT_GREY) + { + *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 65535; + } + else if(mode->colortype == LCT_RGB) + { + *r = 256 * in[i * 6 + 0] + in[i * 6 + 1]; + *g = 256 * in[i * 6 + 2] + in[i * 6 + 3]; + *b = 256 * in[i * 6 + 4] + in[i * 6 + 5]; + if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 65535; + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + *r = *g = *b = 256 * in[i * 4 + 0] + in[i * 4 + 1]; + *a = 256 * in[i * 4 + 2] + in[i * 4 + 3]; + } + else if(mode->colortype == LCT_RGBA) + { + *r = 256 * in[i * 8 + 0] + in[i * 8 + 1]; + *g = 256 * in[i * 8 + 2] + in[i * 8 + 3]; + *b = 256 * in[i * 8 + 4] + in[i * 8 + 5]; + *a = 256 * in[i * 8 + 6] + in[i * 8 + 7]; + } +} + +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h) +{ + size_t i; + ColorTree tree; + size_t numpixels = w * h; + + if(lodepng_color_mode_equal(mode_out, mode_in)) + { + size_t numbytes = lodepng_get_raw_size(w, h, mode_in); + for(i = 0; i < numbytes; i++) out[i] = in[i]; + return 0; + } + + if(mode_out->colortype == LCT_PALETTE) + { + size_t palsize = 1u << mode_out->bitdepth; + if(mode_out->palettesize < palsize) palsize = mode_out->palettesize; + color_tree_init(&tree); + for(i = 0; i < palsize; i++) + { + unsigned char* p = &mode_out->palette[i * 4]; + color_tree_add(&tree, p[0], p[1], p[2], p[3], i); + } + } + + if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) + { + for(i = 0; i < numpixels; i++) + { + unsigned short r = 0, g = 0, b = 0, a = 0; + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + rgba16ToPixel(out, i, mode_out, r, g, b, a); + } + } + else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) + { + getPixelColorsRGBA8(out, numpixels, 1, in, mode_in); + } + else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) + { + getPixelColorsRGBA8(out, numpixels, 0, in, mode_in); + } + else + { + unsigned char r = 0, g = 0, b = 0, a = 0; + for(i = 0; i < numpixels; i++) + { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); + rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a); + } + } + + if(mode_out->colortype == LCT_PALETTE) + { + color_tree_cleanup(&tree); + } + + return 0; /*no error (this function currently never has one, but maybe OOM detection added later.)*/ +} + +#ifdef LODEPNG_COMPILE_ENCODER + +void lodepng_color_profile_init(LodePNGColorProfile* profile) +{ + profile->colored = 0; + profile->key = 0; + profile->alpha = 0; + profile->key_r = profile->key_g = profile->key_b = 0; + profile->numcolors = 0; + profile->bits = 1; +} + +/*function used for debug purposes with C++*/ +/*void printColorProfile(LodePNGColorProfile* p) +{ + std::cout << "colored: " << (int)p->colored << ", "; + std::cout << "key: " << (int)p->key << ", "; + std::cout << "key_r: " << (int)p->key_r << ", "; + std::cout << "key_g: " << (int)p->key_g << ", "; + std::cout << "key_b: " << (int)p->key_b << ", "; + std::cout << "alpha: " << (int)p->alpha << ", "; + std::cout << "numcolors: " << (int)p->numcolors << ", "; + std::cout << "bits: " << (int)p->bits << std::endl; +}*/ + +/*Returns how many bits needed to represent given value (max 8 bit)*/ +unsigned getValueRequiredBits(unsigned char value) +{ + if(value == 0 || value == 255) return 1; + /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/ + if(value % 17 == 0) return value % 85 == 0 ? 2 : 4; + return 8; +} + +/*profile must already have been inited with mode. +It's ok to set some parameters of profile to done already.*/ +unsigned get_color_profile(LodePNGColorProfile* profile, + const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* mode) +{ + unsigned error = 0; + size_t i; + ColorTree tree; + size_t numpixels = w * h; + + unsigned colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0; + unsigned alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1; + unsigned numcolors_done = 0; + unsigned bpp = lodepng_get_bpp(mode); + unsigned bits_done = bpp == 1 ? 1 : 0; + unsigned maxnumcolors = 257; + unsigned sixteen = 0; + if(bpp <= 8) maxnumcolors = bpp == 1 ? 2 : (bpp == 2 ? 4 : (bpp == 4 ? 16 : 256)); + + color_tree_init(&tree); + + /*Check if the 16-bit input is truly 16-bit*/ + if(mode->bitdepth == 16) + { + unsigned short r, g, b, a; + for(i = 0; i < numpixels; i++) + { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + if(r % 257u != 0 || g % 257u != 0 || b % 257u != 0 || a % 257u != 0) /*first and second byte differ*/ + { + sixteen = 1; + break; + } + } + } + + if(sixteen) + { + unsigned short r = 0, g = 0, b = 0, a = 0; + profile->bits = 16; + bits_done = numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/ + + for(i = 0; i < numpixels; i++) + { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + + if(!colored_done && (r != g || r != b)) + { + profile->colored = 1; + colored_done = 1; + } + + if(!alpha_done) + { + unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); + if(a != 65535 && (a != 0 || (profile->key && !matchkey))) + { + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + else if(a == 0 && !profile->alpha && !profile->key) + { + profile->key = 1; + profile->key_r = r; + profile->key_g = g; + profile->key_b = b; + } + else if(a == 65535 && profile->key && matchkey) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + } + } + + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } + } + else /* < 16-bit */ + { + for(i = 0; i < numpixels; i++) + { + unsigned char r = 0, g = 0, b = 0, a = 0; + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode); + + if(!bits_done && profile->bits < 8) + { + /*only r is checked, < 8 bits is only relevant for greyscale*/ + unsigned bits = getValueRequiredBits(r); + if(bits > profile->bits) profile->bits = bits; + } + bits_done = (profile->bits >= bpp); + + if(!colored_done && (r != g || r != b)) + { + profile->colored = 1; + colored_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no colored modes with less than 8-bit per channel*/ + } + + if(!alpha_done) + { + unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); + if(a != 255 && (a != 0 || (profile->key && !matchkey))) + { + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + else if(a == 0 && !profile->alpha && !profile->key) + { + profile->key = 1; + profile->key_r = r; + profile->key_g = g; + profile->key_b = b; + } + else if(a == 255 && profile->key && matchkey) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + } + + if(!numcolors_done) + { + if(!color_tree_has(&tree, r, g, b, a)) + { + color_tree_add(&tree, r, g, b, a, profile->numcolors); + if(profile->numcolors < 256) + { + unsigned char* p = profile->palette; + unsigned n = profile->numcolors; + p[n * 4 + 0] = r; + p[n * 4 + 1] = g; + p[n * 4 + 2] = b; + p[n * 4 + 3] = a; + } + profile->numcolors++; + numcolors_done = profile->numcolors >= maxnumcolors; + } + } + + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } + + /*make the profile's key always 16-bit for consistency - repeat each byte twice*/ + profile->key_r *= 257; + profile->key_g *= 257; + profile->key_b *= 257; + } + + color_tree_cleanup(&tree); + return error; +} + +/*Automatically chooses color type that gives smallest amount of bits in the +output image, e.g. grey if there are only greyscale pixels, palette if there +are less than 256 colors, ... +Updates values of mode with a potentially smaller color model. mode_out should +contain the user chosen color model, but will be overwritten with the new chosen one.*/ +unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in) +{ + LodePNGColorProfile prof; + unsigned error = 0; + unsigned i, n, palettebits, grey_ok, palette_ok; + + lodepng_color_profile_init(&prof); + error = get_color_profile(&prof, image, w, h, mode_in); + if(error) return error; + mode_out->key_defined = 0; + + if(prof.key && w * h <= 16) prof.alpha = 1; /*too few pixels to justify tRNS chunk overhead*/ + grey_ok = !prof.colored && !prof.alpha; /*grey without alpha, with potentially low bits*/ + n = prof.numcolors; + palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8)); + palette_ok = n <= 256 && (n * 2 < w * h) && prof.bits <= 8; + if(w * h < n * 2) palette_ok = 0; /*don't add palette overhead if image has only a few pixels*/ + if(grey_ok && prof.bits <= palettebits) palette_ok = 0; /*grey is less overhead*/ + + if(palette_ok) + { + unsigned char* p = prof.palette; + lodepng_palette_clear(mode_out); /*remove potential earlier palette*/ + for(i = 0; i < prof.numcolors; i++) + { + error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]); + if(error) break; + } + + mode_out->colortype = LCT_PALETTE; + mode_out->bitdepth = palettebits; + + if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize + && mode_in->bitdepth == mode_out->bitdepth) + { + /*If input should have same palette colors, keep original to preserve its order and prevent conversion*/ + lodepng_color_mode_cleanup(mode_out); + lodepng_color_mode_copy(mode_out, mode_in); + } + } + else /*8-bit or 16-bit per channel*/ + { + mode_out->bitdepth = prof.bits; + mode_out->colortype = prof.alpha ? (prof.colored ? LCT_RGBA : LCT_GREY_ALPHA) + : (prof.colored ? LCT_RGB : LCT_GREY); + + if(prof.key && !prof.alpha) + { + unsigned mask = (1u << mode_out->bitdepth) - 1u; /*profile always uses 16-bit, mask converts it*/ + mode_out->key_r = prof.key_r & mask; + mode_out->key_g = prof.key_g & mask; + mode_out->key_b = prof.key_b & mask; + mode_out->key_defined = 1; + } + } + + return error; +} + +#endif /* #ifdef LODEPNG_COMPILE_ENCODER */ + +/* +Paeth predicter, used by PNG filter type 4 +The parameters are of type short, but should come from unsigned chars, the shorts +are only needed to make the paeth calculation correct. +*/ +static unsigned char paethPredictor(short a, short b, short c) +{ + short pa = abs(b - c); + short pb = abs(a - c); + short pc = abs(a + b - c - c); + + if(pc < pa && pc < pb) return (unsigned char)c; + else if(pb < pa) return (unsigned char)b; + else return (unsigned char)a; +} + +/*shared values used by multiple Adam7 related functions*/ + +static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ +static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ +static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ +static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ + +/* +Outputs various dimensions and positions in the image related to the Adam7 reduced images. +passw: output containing the width of the 7 passes +passh: output containing the height of the 7 passes +filter_passstart: output containing the index of the start and end of each + reduced image with filter bytes +padded_passstart output containing the index of the start and end of each + reduced image when without filter bytes but with padded scanlines +passstart: output containing the index of the start and end of each reduced + image without padding between scanlines, but still padding between the images +w, h: width and height of non-interlaced image +bpp: bits per pixel +"padded" is only relevant if bpp is less than 8 and a scanline or image does not + end at a full byte +*/ +static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], + size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) +{ + /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/ + unsigned i; + + /*calculate width and height in pixels of each pass*/ + for(i = 0; i < 7; i++) + { + passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i]; + passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i]; + if(passw[i] == 0) passh[i] = 0; + if(passh[i] == 0) passw[i] = 0; + } + + filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; + for(i = 0; i < 7; i++) + { + /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/ + filter_passstart[i + 1] = filter_passstart[i] + + ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0); + /*bits padded if needed to fill full byte at end of each scanline*/ + padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8); + /*only padded at end of reduced image*/ + passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8; + } +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Decoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*read the information from the header and store it in the LodePNGInfo. return value is error*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, + const unsigned char* in, size_t insize) +{ + LodePNGInfo* info = &state->info_png; + if(insize == 0 || in == 0) + { + CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/ + } + if(insize < 29) + { + CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/ + } + + /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/ + lodepng_info_cleanup(info); + lodepng_info_init(info); + + if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 + || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) + { + CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/ + } + if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') + { + CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/ + } + + /*read the values given in the header*/ + *w = lodepng_read32bitInt(&in[16]); + *h = lodepng_read32bitInt(&in[20]); + info->color.bitdepth = in[24]; + info->color.colortype = (LodePNGColorType)in[25]; + info->compression_method = in[26]; + info->filter_method = in[27]; + info->interlace_method = in[28]; + + if(!state->decoder.ignore_crc) + { + unsigned CRC = lodepng_read32bitInt(&in[29]); + unsigned checksum = lodepng_crc32(&in[12], 17); + if(CRC != checksum) + { + CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/ + } + } + + /*error: only compression method 0 is allowed in the specification*/ + if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32); + /*error: only filter method 0 is allowed in the specification*/ + if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33); + /*error: only interlace methods 0 and 1 exist in the specification*/ + if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34); + + state->error = checkColorValidity(info->color.colortype, info->color.bitdepth); + return state->error; +} + +static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, + size_t bytewidth, unsigned char filterType, size_t length) +{ + /* + For PNG filter method 0 + unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, + the filter works byte per byte (bytewidth = 1) + precon is the previous unfiltered scanline, recon the result, scanline the current one + the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead + recon and scanline MAY be the same memory address! precon must be disjoint. + */ + + size_t i; + switch(filterType) + { + case 0: + for(i = 0; i < length; i++) recon[i] = scanline[i]; + break; + case 1: + for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth]; + break; + case 2: + if(precon) + { + for(i = 0; i < length; i++) recon[i] = scanline[i] + precon[i]; + } + else + { + for(i = 0; i < length; i++) recon[i] = scanline[i]; + } + break; + case 3: + if(precon) + { + for(i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2; + for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2); + } + else + { + for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2; + } + break; + case 4: + if(precon) + { + for(i = 0; i < bytewidth; i++) + { + recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ + } + for(i = bytewidth; i < length; i++) + { + recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); + } + } + else + { + for(i = 0; i < bytewidth; i++) + { + recon[i] = scanline[i]; + } + for(i = bytewidth; i < length; i++) + { + /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ + recon[i] = (scanline[i] + recon[i - bytewidth]); + } + } + break; + default: return 36; /*error: unexisting filter type given*/ + } + return 0; +} + +static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + /* + For PNG filter method 0 + this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times) + out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline + w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel + in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes) + */ + + unsigned y; + unsigned char* prevline = 0; + + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7) / 8; + size_t linebytes = (w * bpp + 7) / 8; + + for(y = 0; y < h; y++) + { + size_t outindex = linebytes * y; + size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + unsigned char filterType = in[inindex]; + + CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes)); + + prevline = &out[outindex]; + } + + return 0; +} + +/* +in: Adam7 interlaced image, with no padding bits between scanlines, but between + reduced images so that each reduced image starts at a byte. +out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h +bpp: bits per pixel +out has the following size in bits: w * h * bpp. +in is possibly bigger due to padding bits between reduced images. +out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation +(because that's likely a little bit faster) +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + size_t bytewidth = bpp / 8; + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; + size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + for(b = 0; b < bytewidth; b++) + { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } + else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + for(b = 0; b < bpp; b++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/ + setBitOfReversedStream0(&obp, out, bit); + } + } + } + } +} + +static void removePaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) +{ + /* + After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need + to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers + for the Adam7 code, the color convert code and the output to the user. + in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must + have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits + also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7 + only useful if (ilinebits - olinebits) is a value in the range 1..7 + */ + unsigned y; + size_t diff = ilinebits - olinebits; + size_t ibp = 0, obp = 0; /*input and output bit pointers*/ + for(y = 0; y < h; y++) + { + size_t x; + for(x = 0; x < olinebits; x++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + ibp += diff; + } +} + +/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from +the IDAT chunks (with filter index bytes and possible padding bits) +return value is error*/ +static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, + unsigned w, unsigned h, const LodePNGInfo* info_png) +{ + /* + This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. + Steps: + *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8) + *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace + NOTE: the in buffer will be overwritten with intermediate data! + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + if(bpp == 0) return 31; /*error: invalid colortype*/ + + if(info_png->interlace_method == 0) + { + if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) + { + CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp)); + removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h); + } + /*we can immediatly filter into the out buffer, no other steps needed*/ + else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp)); + } + else /*interlace_method is 1 (Adam7)*/ + { + unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + for(i = 0; i < 7; i++) + { + CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp)); + /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, + move bytes instead of bits or move not at all*/ + if(bpp < 8) + { + /*remove padding bits in scanlines; after this there still may be padding + bits between the different reduced images: each reduced image still starts nicely at a byte*/ + removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, + ((passw[i] * bpp + 7) / 8) * 8, passh[i]); + } + } + + Adam7_deinterlace(out, in, w, h, bpp); + } + + return 0; +} + +static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) +{ + unsigned pos = 0, i; + if(color->palette) lodepng_free(color->palette); + color->palettesize = chunkLength / 3; + color->palette = (unsigned char*)lodepng_malloc(4 * color->palettesize); + if(!color->palette && color->palettesize) + { + color->palettesize = 0; + return 83; /*alloc fail*/ + } + if(color->palettesize > 256) return 38; /*error: palette too big*/ + + for(i = 0; i < color->palettesize; i++) + { + color->palette[4 * i + 0] = data[pos++]; /*R*/ + color->palette[4 * i + 1] = data[pos++]; /*G*/ + color->palette[4 * i + 2] = data[pos++]; /*B*/ + color->palette[4 * i + 3] = 255; /*alpha*/ + } + + return 0; /* OK */ +} + +static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) +{ + unsigned i; + if(color->colortype == LCT_PALETTE) + { + /*error: more alpha values given than there are palette entries*/ + if(chunkLength > color->palettesize) return 38; + + for(i = 0; i < chunkLength; i++) color->palette[4 * i + 3] = data[i]; + } + else if(color->colortype == LCT_GREY) + { + /*error: this chunk must be 2 bytes for greyscale image*/ + if(chunkLength != 2) return 30; + + color->key_defined = 1; + color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1]; + } + else if(color->colortype == LCT_RGB) + { + /*error: this chunk must be 6 bytes for RGB image*/ + if(chunkLength != 6) return 41; + + color->key_defined = 1; + color->key_r = 256u * data[0] + data[1]; + color->key_g = 256u * data[2] + data[3]; + color->key_b = 256u * data[4] + data[5]; + } + else return 42; /*error: tRNS chunk not allowed for other color models*/ + + return 0; /* OK */ +} + + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*background color chunk (bKGD)*/ +static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(info->color.colortype == LCT_PALETTE) + { + /*error: this chunk must be 1 byte for indexed color image*/ + if(chunkLength != 1) return 43; + + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = data[0]; + } + else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) + { + /*error: this chunk must be 2 bytes for greyscale image*/ + if(chunkLength != 2) return 44; + + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = 256u * data[0] + data[1]; + } + else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) + { + /*error: this chunk must be 6 bytes for greyscale image*/ + if(chunkLength != 6) return 45; + + info->background_defined = 1; + info->background_r = 256u * data[0] + data[1]; + info->background_g = 256u * data[2] + data[3]; + info->background_b = 256u * data[4] + data[5]; + } + + return 0; /* OK */ +} + +/*text chunk (tEXt)*/ +static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + char *key = 0, *str = 0; + unsigned i; + + while(!error) /*not really a while loop, only used to break on error*/ + { + unsigned length, string2_begin; + + length = 0; + while(length < chunkLength && data[length] != 0) length++; + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i < length; i++) key[i] = (char)data[i]; + + string2_begin = length + 1; /*skip keyword null terminator*/ + + length = chunkLength < string2_begin ? 0 : chunkLength - string2_begin; + str = (char*)lodepng_malloc(length + 1); + if(!str) CERROR_BREAK(error, 83); /*alloc fail*/ + + str[length] = 0; + for(i = 0; i < length; i++) str[i] = (char)data[string2_begin + i]; + + error = lodepng_add_text(info, key, str); + + break; + } + + lodepng_free(key); + lodepng_free(str); + + return error; +} + +/*compressed text chunk (zTXt)*/ +static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, + const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + unsigned i; + + unsigned length, string2_begin; + char *key = 0; + ucvector decoded; + + ucvector_init(&decoded); + + while(!error) /*not really a while loop, only used to break on error*/ + { + for(length = 0; length < chunkLength && data[length] != 0; length++) ; + if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i < length; i++) key[i] = (char)data[i]; + + if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + string2_begin = length + 2; + if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + + length = chunkLength - string2_begin; + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&decoded.data, &decoded.size, + (unsigned char*)(&data[string2_begin]), + length, zlibsettings); + if(error) break; + ucvector_push_back(&decoded, 0); + + error = lodepng_add_text(info, key, (char*)decoded.data); + + break; + } + + lodepng_free(key); + ucvector_cleanup(&decoded); + + return error; +} + +/*international text chunk (iTXt)*/ +static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, + const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + unsigned i; + + unsigned length, begin, compressed; + char *key = 0, *langtag = 0, *transkey = 0; + ucvector decoded; + ucvector_init(&decoded); + + while(!error) /*not really a while loop, only used to break on error*/ + { + /*Quick check if the chunk length isn't too small. Even without check + it'd still fail with other error checks below if it's too short. This just gives a different error code.*/ + if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/ + + /*read the key*/ + for(length = 0; length < chunkLength && data[length] != 0; length++) ; + if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i < length; i++) key[i] = (char)data[i]; + + /*read the compression method*/ + compressed = data[length + 1]; + if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty for the next 3 texts*/ + + /*read the langtag*/ + begin = length + 3; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; i++) length++; + + langtag = (char*)lodepng_malloc(length + 1); + if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/ + + langtag[length] = 0; + for(i = 0; i < length; i++) langtag[i] = (char)data[begin + i]; + + /*read the transkey*/ + begin += length + 1; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; i++) length++; + + transkey = (char*)lodepng_malloc(length + 1); + if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/ + + transkey[length] = 0; + for(i = 0; i < length; i++) transkey[i] = (char)data[begin + i]; + + /*read the actual text*/ + begin += length + 1; + + length = chunkLength < begin ? 0 : chunkLength - begin; + + if(compressed) + { + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&decoded.data, &decoded.size, + (unsigned char*)(&data[begin]), + length, zlibsettings); + if(error) break; + if(decoded.allocsize < decoded.size) decoded.allocsize = decoded.size; + ucvector_push_back(&decoded, 0); + } + else + { + if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(error, 83 /*alloc fail*/); + + decoded.data[length] = 0; + for(i = 0; i < length; i++) decoded.data[i] = data[begin + i]; + } + + error = lodepng_add_itext(info, key, langtag, transkey, (char*)decoded.data); + + break; + } + + lodepng_free(key); + lodepng_free(langtag); + lodepng_free(transkey); + ucvector_cleanup(&decoded); + + return error; +} + +static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(chunkLength != 7) return 73; /*invalid tIME chunk size*/ + + info->time_defined = 1; + info->time.year = 256u * data[0] + data[1]; + info->time.month = data[2]; + info->time.day = data[3]; + info->time.hour = data[4]; + info->time.minute = data[5]; + info->time.second = data[6]; + + return 0; /* OK */ +} + +static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/ + + info->phys_defined = 1; + info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; + info->phys_unit = data[8]; + + return 0; /* OK */ +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/ +static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) +{ + unsigned char IEND = 0; + const unsigned char* chunk; + size_t i; + ucvector idat; /*the data from idat chunks*/ + ucvector scanlines; + size_t predict; + + /*for unknown chunk order*/ + unsigned unknown = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + + /*provide some proper output values if error will happen*/ + *out = 0; + + state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/ + if(state->error) return; + + ucvector_init(&idat); + chunk = &in[33]; /*first byte of the first chunk after the header*/ + + /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. + IDAT data is put at the start of the in buffer*/ + while(!IEND && !state->error) + { + unsigned chunkLength; + const unsigned char* data; /*the data in the chunk*/ + + /*error: size of the in buffer too small to contain next chunk*/ + if((size_t)((chunk - in) + 12) > insize || chunk < in) CERROR_BREAK(state->error, 30); + + /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/ + chunkLength = lodepng_chunk_length(chunk); + /*error: chunk length larger than the max PNG chunk size*/ + if(chunkLength > 2147483647) CERROR_BREAK(state->error, 63); + + if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) + { + CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/ + } + + data = lodepng_chunk_data_const(chunk); + + /*IDAT chunk, containing compressed image data*/ + if(lodepng_chunk_type_equals(chunk, "IDAT")) + { + size_t oldsize = idat.size; + if(!ucvector_resize(&idat, oldsize + chunkLength)) CERROR_BREAK(state->error, 83 /*alloc fail*/); + for(i = 0; i < chunkLength; i++) idat.data[oldsize + i] = data[i]; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 3; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + /*IEND chunk*/ + else if(lodepng_chunk_type_equals(chunk, "IEND")) + { + IEND = 1; + } + /*palette chunk (PLTE)*/ + else if(lodepng_chunk_type_equals(chunk, "PLTE")) + { + state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 2; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + /*palette transparency chunk (tRNS)*/ + else if(lodepng_chunk_type_equals(chunk, "tRNS")) + { + state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength); + if(state->error) break; + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*background color chunk (bKGD)*/ + else if(lodepng_chunk_type_equals(chunk, "bKGD")) + { + state->error = readChunk_bKGD(&state->info_png, data, chunkLength); + if(state->error) break; + } + /*text chunk (tEXt)*/ + else if(lodepng_chunk_type_equals(chunk, "tEXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_tEXt(&state->info_png, data, chunkLength); + if(state->error) break; + } + } + /*compressed text chunk (zTXt)*/ + else if(lodepng_chunk_type_equals(chunk, "zTXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + if(state->error) break; + } + } + /*international text chunk (iTXt)*/ + else if(lodepng_chunk_type_equals(chunk, "iTXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + if(state->error) break; + } + } + else if(lodepng_chunk_type_equals(chunk, "tIME")) + { + state->error = readChunk_tIME(&state->info_png, data, chunkLength); + if(state->error) break; + } + else if(lodepng_chunk_type_equals(chunk, "pHYs")) + { + state->error = readChunk_pHYs(&state->info_png, data, chunkLength); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + else /*it's not an implemented chunk type, so ignore it: skip over the data*/ + { + /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ + if(!lodepng_chunk_ancillary(chunk)) CERROR_BREAK(state->error, 69); + + unknown = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(state->decoder.remember_unknown_chunks) + { + state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1], + &state->info_png.unknown_chunks_size[critical_pos - 1], chunk); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + + if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/ + { + if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/ + } + + if(!IEND) chunk = lodepng_chunk_next_const(chunk); + } + + ucvector_init(&scanlines); + /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation. + The prediction is currently not correct for interlaced PNG images.*/ + predict = lodepng_get_raw_size_idat(*w, *h, &state->info_png.color) + *h; + if(!state->error && !ucvector_reserve(&scanlines, predict)) state->error = 83; /*alloc fail*/ + if(!state->error) + { + state->error = zlib_decompress(&scanlines.data, &scanlines.size, idat.data, + idat.size, &state->decoder.zlibsettings); + } + ucvector_cleanup(&idat); + + if(!state->error) + { + ucvector outv; + ucvector_init(&outv); + if(!ucvector_resizev(&outv, + lodepng_get_raw_size(*w, *h, &state->info_png.color), 0)) state->error = 83; /*alloc fail*/ + if(!state->error) state->error = postProcessScanlines(outv.data, scanlines.data, *w, *h, &state->info_png); + *out = outv.data; + } + ucvector_cleanup(&scanlines); +} + +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) +{ + *out = 0; + decodeGeneric(out, w, h, state, in, insize); + if(state->error) return state->error; + if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) + { + /*same color type, no copying or converting of data needed*/ + /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype + the raw image has to the end user*/ + if(!state->decoder.color_convert) + { + state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color); + if(state->error) return state->error; + } + } + else + { + /*color conversion needed; sort of copy of the data*/ + unsigned char* data = *out; + size_t outsize; + + /*TODO: check if this works according to the statement in the documentation: "The converter can convert + from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/ + if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA) + && !(state->info_raw.bitdepth == 8)) + { + return 56; /*unsupported color mode conversion*/ + } + + outsize = lodepng_get_raw_size(*w, *h, &state->info_raw); + *out = (unsigned char*)lodepng_malloc(outsize); + if(!(*out)) + { + state->error = 83; /*alloc fail*/ + } + else state->error = lodepng_convert(*out, data, &state->info_raw, + &state->info_png.color, *w, *h); + lodepng_free(data); + } + return state->error; +} + +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + error = lodepng_decode(out, w, h, &state, in, insize); + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) +{ + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8); +} + +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) +{ + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error; + error = lodepng_load_file(&buffer, &buffersize, filename); + if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth); + lodepng_free(buffer); + return error; +} + +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) +{ + return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8); +} + +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) +{ + return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) +{ + settings->color_convert = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->read_text_chunks = 1; + settings->remember_unknown_chunks = 0; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + settings->ignore_crc = 0; + lodepng_decompress_settings_init(&settings->zlibsettings); +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) + +void lodepng_state_init(LodePNGState* state) +{ +#ifdef LODEPNG_COMPILE_DECODER + lodepng_decoder_settings_init(&state->decoder); +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + lodepng_encoder_settings_init(&state->encoder); +#endif /*LODEPNG_COMPILE_ENCODER*/ + lodepng_color_mode_init(&state->info_raw); + lodepng_info_init(&state->info_png); + state->error = 1; +} + +void lodepng_state_cleanup(LodePNGState* state) +{ + lodepng_color_mode_cleanup(&state->info_raw); + lodepng_info_cleanup(&state->info_png); +} + +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) +{ + lodepng_state_cleanup(dest); + *dest = *source; + lodepng_color_mode_init(&dest->info_raw); + lodepng_info_init(&dest->info_png); + dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return; + dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return; +} + +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Encoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*chunkName must be string of 4 characters*/ +static unsigned addChunk(ucvector* out, const char* chunkName, const unsigned char* data, size_t length) +{ + CERROR_TRY_RETURN(lodepng_chunk_create(&out->data, &out->size, (unsigned)length, chunkName, data)); + out->allocsize = out->size; /*fix the allocsize again*/ + return 0; +} + +static void writeSignature(ucvector* out) +{ + /*8 bytes PNG signature, aka the magic bytes*/ + ucvector_push_back(out, 137); + ucvector_push_back(out, 80); + ucvector_push_back(out, 78); + ucvector_push_back(out, 71); + ucvector_push_back(out, 13); + ucvector_push_back(out, 10); + ucvector_push_back(out, 26); + ucvector_push_back(out, 10); +} + +static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method) +{ + unsigned error = 0; + ucvector header; + ucvector_init(&header); + + lodepng_add32bitInt(&header, w); /*width*/ + lodepng_add32bitInt(&header, h); /*height*/ + ucvector_push_back(&header, (unsigned char)bitdepth); /*bit depth*/ + ucvector_push_back(&header, (unsigned char)colortype); /*color type*/ + ucvector_push_back(&header, 0); /*compression method*/ + ucvector_push_back(&header, 0); /*filter method*/ + ucvector_push_back(&header, interlace_method); /*interlace method*/ + + error = addChunk(out, "IHDR", header.data, header.size); + ucvector_cleanup(&header); + + return error; +} + +static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) +{ + unsigned error = 0; + size_t i; + ucvector PLTE; + ucvector_init(&PLTE); + for(i = 0; i < info->palettesize * 4; i++) + { + /*add all channels except alpha channel*/ + if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]); + } + error = addChunk(out, "PLTE", PLTE.data, PLTE.size); + ucvector_cleanup(&PLTE); + + return error; +} + +static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) +{ + unsigned error = 0; + size_t i; + ucvector tRNS; + ucvector_init(&tRNS); + if(info->colortype == LCT_PALETTE) + { + size_t amount = info->palettesize; + /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/ + for(i = info->palettesize; i > 0; i--) + { + if(info->palette[4 * (i - 1) + 3] == 255) amount--; + else break; + } + /*add only alpha channel*/ + for(i = 0; i < amount; i++) ucvector_push_back(&tRNS, info->palette[4 * i + 3]); + } + else if(info->colortype == LCT_GREY) + { + if(info->key_defined) + { + ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256)); + } + } + else if(info->colortype == LCT_RGB) + { + if(info->key_defined) + { + ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_g / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_g % 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_b / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_b % 256)); + } + } + + error = addChunk(out, "tRNS", tRNS.data, tRNS.size); + ucvector_cleanup(&tRNS); + + return error; +} + +static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize, + LodePNGCompressSettings* zlibsettings) +{ + ucvector zlibdata; + unsigned error = 0; + + /*compress with the Zlib compressor*/ + ucvector_init(&zlibdata); + error = zlib_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings); + if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size); + ucvector_cleanup(&zlibdata); + + return error; +} + +static unsigned addChunk_IEND(ucvector* out) +{ + unsigned error = 0; + error = addChunk(out, "IEND", 0, 0); + return error; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) +{ + unsigned error = 0; + size_t i; + ucvector text; + ucvector_init(&text); + for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&text, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&text, 0); /*0 termination char*/ + for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&text, (unsigned char)textstring[i]); + error = addChunk(out, "tEXt", text.data, text.size); + ucvector_cleanup(&text); + + return error; +} + +static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, + LodePNGCompressSettings* zlibsettings) +{ + unsigned error = 0; + ucvector data, compressed; + size_t i, textsize = strlen(textstring); + + ucvector_init(&data); + ucvector_init(&compressed); + for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&data, 0); /*0 termination char*/ + ucvector_push_back(&data, 0); /*compression method: 0*/ + + error = zlib_compress(&compressed.data, &compressed.size, + (unsigned char*)textstring, textsize, zlibsettings); + if(!error) + { + for(i = 0; i < compressed.size; i++) ucvector_push_back(&data, compressed.data[i]); + error = addChunk(out, "zTXt", data.data, data.size); + } + + ucvector_cleanup(&compressed); + ucvector_cleanup(&data); + return error; +} + +static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag, + const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings) +{ + unsigned error = 0; + ucvector data; + size_t i, textsize = strlen(textstring); + + ucvector_init(&data); + + for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&data, 0); /*null termination char*/ + ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/ + ucvector_push_back(&data, 0); /*compression method*/ + for(i = 0; langtag[i] != 0; i++) ucvector_push_back(&data, (unsigned char)langtag[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + for(i = 0; transkey[i] != 0; i++) ucvector_push_back(&data, (unsigned char)transkey[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + + if(compressed) + { + ucvector compressed_data; + ucvector_init(&compressed_data); + error = zlib_compress(&compressed_data.data, &compressed_data.size, + (unsigned char*)textstring, textsize, zlibsettings); + if(!error) + { + for(i = 0; i < compressed_data.size; i++) ucvector_push_back(&data, compressed_data.data[i]); + } + ucvector_cleanup(&compressed_data); + } + else /*not compressed*/ + { + for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&data, (unsigned char)textstring[i]); + } + + if(!error) error = addChunk(out, "iTXt", data.data, data.size); + ucvector_cleanup(&data); + return error; +} + +static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) +{ + unsigned error = 0; + ucvector bKGD; + ucvector_init(&bKGD); + if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); + } + else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_g / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_g % 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_b / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_b % 256)); + } + else if(info->color.colortype == LCT_PALETTE) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); /*palette index*/ + } + + error = addChunk(out, "bKGD", bKGD.data, bKGD.size); + ucvector_cleanup(&bKGD); + + return error; +} + +static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) +{ + unsigned error = 0; + unsigned char* data = (unsigned char*)lodepng_malloc(7); + if(!data) return 83; /*alloc fail*/ + data[0] = (unsigned char)(time->year / 256); + data[1] = (unsigned char)(time->year % 256); + data[2] = (unsigned char)time->month; + data[3] = (unsigned char)time->day; + data[4] = (unsigned char)time->hour; + data[5] = (unsigned char)time->minute; + data[6] = (unsigned char)time->second; + error = addChunk(out, "tIME", data, 7); + lodepng_free(data); + return error; +} + +static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) +{ + unsigned error = 0; + ucvector data; + ucvector_init(&data); + + lodepng_add32bitInt(&data, info->phys_x); + lodepng_add32bitInt(&data, info->phys_y); + ucvector_push_back(&data, info->phys_unit); + + error = addChunk(out, "pHYs", data.data, data.size); + ucvector_cleanup(&data); + + return error; +} + +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, + size_t length, size_t bytewidth, unsigned char filterType) +{ + size_t i; + switch(filterType) + { + case 0: /*None*/ + for(i = 0; i < length; i++) out[i] = scanline[i]; + break; + case 1: /*Sub*/ + for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth]; + break; + case 2: /*Up*/ + if(prevline) + { + for(i = 0; i < length; i++) out[i] = scanline[i] - prevline[i]; + } + else + { + for(i = 0; i < length; i++) out[i] = scanline[i]; + } + break; + case 3: /*Average*/ + if(prevline) + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i] - prevline[i] / 2; + for(i = bytewidth; i < length; i++) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) / 2); + } + else + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth] / 2; + } + break; + case 4: /*Paeth*/ + if(prevline) + { + /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/ + for(i = 0; i < bytewidth; i++) out[i] = (scanline[i] - prevline[i]); + for(i = bytewidth; i < length; i++) + { + out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth])); + } + } + else + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/ + for(i = bytewidth; i < length; i++) out[i] = (scanline[i] - scanline[i - bytewidth]); + } + break; + default: return; /*unexisting filter type given*/ + } +} + +/* log2 approximation. A slight bit faster than std::log. */ +static float flog2(float f) +{ + float result = 0; + while(f > 32) { result += 4; f /= 16; } + while(f > 2) { result++; f /= 2; } + return result + 1.442695f * (f * f * f / 3 - 3 * f * f / 2 + 3 * f - 1.83333f); +} + +static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* info, const LodePNGEncoderSettings* settings) +{ + /* + For PNG filter method 0 + out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are + the scanlines with 1 extra byte per scanline + */ + + unsigned bpp = lodepng_get_bpp(info); + /*the width of a scanline in bytes, not including the filter type*/ + size_t linebytes = (w * bpp + 7) / 8; + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7) / 8; + const unsigned char* prevline = 0; + unsigned x, y; + unsigned error = 0; + LodePNGFilterStrategy strategy = settings->filter_strategy; + + /* + There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard: + * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. + use fixed filtering, with the filter None). + * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is + not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply + all five filters and select the filter that produces the smallest sum of absolute values per row. + This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true. + + If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed, + but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum + heuristic is used. + */ + if(settings->filter_palette_zero && + (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO; + + if(bpp == 0) return 31; /*error: invalid color type*/ + + if(strategy == LFS_ZERO) + { + for(y = 0; y < h; y++) + { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + out[outindex] = 0; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, 0); + prevline = &in[inindex]; + } + } + else if(strategy == LFS_MINSUM) + { + /*adaptive filtering*/ + size_t sum[5]; + ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned char type, bestType = 0; + + for(type = 0; type < 5; type++) + { + ucvector_init(&attempt[type]); + if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/ + } + + if(!error) + { + for(y = 0; y < h; y++) + { + /*try the 5 filter types*/ + for(type = 0; type < 5; type++) + { + filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); + + /*calculate the sum of the result*/ + sum[type] = 0; + if(type == 0) + { + for(x = 0; x < linebytes; x++) sum[type] += (unsigned char)(attempt[type].data[x]); + } + else + { + for(x = 0; x < linebytes; x++) + { + /*For differences, each byte should be treated as signed, values above 127 are negative + (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there. + This means filtertype 0 is almost never chosen, but that is justified.*/ + unsigned char s = attempt[type].data[x]; + sum[type] += s < 128 ? s : (255U - s); + } + } + + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum[type] < smallest) + { + bestType = type; + smallest = sum[type]; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + } + } + + for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); + } + else if(strategy == LFS_ENTROPY) + { + float sum[5]; + ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ + float smallest = 0; + unsigned type, bestType = 0; + unsigned count[256]; + + for(type = 0; type < 5; type++) + { + ucvector_init(&attempt[type]); + if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/ + } + + for(y = 0; y < h; y++) + { + /*try the 5 filter types*/ + for(type = 0; type < 5; type++) + { + filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); + for(x = 0; x < 256; x++) count[x] = 0; + for(x = 0; x < linebytes; x++) count[attempt[type].data[x]]++; + count[type]++; /*the filter type itself is part of the scanline*/ + sum[type] = 0; + for(x = 0; x < 256; x++) + { + float p = count[x] / (float)(linebytes + 1); + sum[type] += count[x] == 0 ? 0 : flog2(1 / p) * p; + } + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum[type] < smallest) + { + bestType = type; + smallest = sum[type]; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + } + + for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); + } + else if(strategy == LFS_PREDEFINED) + { + for(y = 0; y < h; y++) + { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + unsigned char type = settings->predefined_filters[y]; + out[outindex] = type; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); + prevline = &in[inindex]; + } + } + else if(strategy == LFS_BRUTE_FORCE) + { + /*brute force filter chooser. + deflate the scanline after every filter attempt to see which one deflates best. + This is very slow and gives only slightly smaller, sometimes even larger, result*/ + size_t size[5]; + ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned type = 0, bestType = 0; + unsigned char* dummy; + LodePNGCompressSettings zlibsettings = settings->zlibsettings; + /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose, + to simulate the true case where the tree is the same for the whole image. Sometimes it gives + better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare + cases better compression. It does make this a bit less slow, so it's worth doing this.*/ + zlibsettings.btype = 1; + /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG + images only, so disable it*/ + zlibsettings.custom_zlib = 0; + zlibsettings.custom_deflate = 0; + for(type = 0; type < 5; type++) + { + ucvector_init(&attempt[type]); + ucvector_resize(&attempt[type], linebytes); /*todo: give error if resize failed*/ + } + for(y = 0; y < h; y++) /*try the 5 filter types*/ + { + for(type = 0; type < 5; type++) + { + unsigned testsize = attempt[type].size; + /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/ + + filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); + size[type] = 0; + dummy = 0; + zlib_compress(&dummy, &size[type], attempt[type].data, testsize, &zlibsettings); + lodepng_free(dummy); + /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || size[type] < smallest) + { + bestType = type; + smallest = size[type]; + } + } + prevline = &in[y * linebytes]; + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + } + for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); + } + else return 88; /* unknown filter strategy */ + + return error; +} + +static void addPaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) +{ + /*The opposite of the removePaddingBits function + olinebits must be >= ilinebits*/ + unsigned y; + size_t diff = olinebits - ilinebits; + size_t obp = 0, ibp = 0; /*bit pointers*/ + for(y = 0; y < h; y++) + { + size_t x; + for(x = 0; x < ilinebits; x++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + /*obp += diff; --> no, fill in some value in the padding bits too, to avoid + "Use of uninitialised value of size ###" warning from valgrind*/ + for(x = 0; x < diff; x++) setBitOfReversedStream(&obp, out, 0); + } +} + +/* +in: non-interlaced image with size w*h +out: the same pixels, but re-ordered according to PNG's Adam7 interlacing, with + no padding bits between scanlines, but between reduced images so that each + reduced image starts at a byte. +bpp: bits per pixel +there are no padding bits, not between scanlines, not between reduced images +in has the following size in bits: w * h * bpp. +out is possibly bigger due to padding bits between reduced images +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + size_t bytewidth = bpp / 8; + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; + for(b = 0; b < bytewidth; b++) + { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } + else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + for(b = 0; b < bpp; b++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + } + } + } +} + +/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image. +return value is error**/ +static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, + unsigned w, unsigned h, + const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) +{ + /* + This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: + *) if no Adam7: 1) add padding bits (= posible extra bits per scanline if bpp < 8) 2) filter + *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + unsigned error = 0; + + if(info_png->interlace_method == 0) + { + *outsize = h + (h * ((w * bpp + 7) / 8)); /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!(*out) && (*outsize)) error = 83; /*alloc fail*/ + + if(!error) + { + /*non multiple of 8 bits per scanline, padding bits needed per scanline*/ + if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) + { + unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7) / 8)); + if(!padded) error = 83; /*alloc fail*/ + if(!error) + { + addPaddingBits(padded, in, ((w * bpp + 7) / 8) * 8, w * bpp, h); + error = filter(*out, padded, w, h, &info_png->color, settings); + } + lodepng_free(padded); + } + else + { + /*we can immediatly filter into the out buffer, no other steps needed*/ + error = filter(*out, in, w, h, &info_png->color, settings); + } + } + } + else /*interlace_method is 1 (Adam7)*/ + { + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned char* adam7; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!(*out)) error = 83; /*alloc fail*/ + + adam7 = (unsigned char*)lodepng_malloc(passstart[7]); + if(!adam7 && passstart[7]) error = 83; /*alloc fail*/ + + if(!error) + { + unsigned i; + + Adam7_interlace(adam7, in, w, h, bpp); + for(i = 0; i < 7; i++) + { + if(bpp < 8) + { + unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]); + if(!padded) ERROR_BREAK(83); /*alloc fail*/ + addPaddingBits(padded, &adam7[passstart[i]], + ((passw[i] * bpp + 7) / 8) * 8, passw[i] * bpp, passh[i]); + error = filter(&(*out)[filter_passstart[i]], padded, + passw[i], passh[i], &info_png->color, settings); + lodepng_free(padded); + } + else + { + error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], + passw[i], passh[i], &info_png->color, settings); + } + + if(error) break; + } + } + + lodepng_free(adam7); + } + + return error; +} + +/* +palette must have 4 * palettesize bytes allocated, and given in format RGBARGBARGBARGBA... +returns 0 if the palette is opaque, +returns 1 if the palette has a single color with alpha 0 ==> color key +returns 2 if the palette is semi-translucent. +*/ +static unsigned getPaletteTranslucency(const unsigned char* palette, size_t palettesize) +{ + size_t i; + unsigned key = 0; + unsigned r = 0, g = 0, b = 0; /*the value of the color with alpha 0, so long as color keying is possible*/ + for(i = 0; i < palettesize; i++) + { + if(!key && palette[4 * i + 3] == 0) + { + r = palette[4 * i + 0]; g = palette[4 * i + 1]; b = palette[4 * i + 2]; + key = 1; + i = (size_t)(-1); /*restart from beginning, to detect earlier opaque colors with key's value*/ + } + else if(palette[4 * i + 3] != 255) return 2; + /*when key, no opaque RGB may have key's RGB*/ + else if(key && r == palette[i * 4 + 0] && g == palette[i * 4 + 1] && b == palette[i * 4 + 2]) return 2; + } + return key; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) +{ + unsigned char* inchunk = data; + while((size_t)(inchunk - data) < datasize) + { + CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk)); + out->allocsize = out->size; /*fix the allocsize again*/ + inchunk = lodepng_chunk_next(inchunk); + } + return 0; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state) +{ + LodePNGInfo info; + ucvector outv; + unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/ + size_t datasize = 0; + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + state->error = 0; + + lodepng_info_init(&info); + lodepng_info_copy(&info, &state->info_png); + + if((info.color.colortype == LCT_PALETTE || state->encoder.force_palette) + && (info.color.palettesize == 0 || info.color.palettesize > 256)) + { + state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/ + return state->error; + } + + if(state->encoder.auto_convert) + { + state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw); + } + if(state->error) return state->error; + + if(state->encoder.zlibsettings.btype > 2) + { + CERROR_RETURN_ERROR(state->error, 61); /*error: unexisting btype*/ + } + if(state->info_png.interlace_method > 1) + { + CERROR_RETURN_ERROR(state->error, 71); /*error: unexisting interlace mode*/ + } + + state->error = checkColorValidity(info.color.colortype, info.color.bitdepth); + if(state->error) return state->error; /*error: unexisting color type given*/ + state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); + if(state->error) return state->error; /*error: unexisting color type given*/ + + if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) + { + unsigned char* converted; + size_t size = (w * h * lodepng_get_bpp(&info.color) + 7) / 8; + + converted = (unsigned char*)lodepng_malloc(size); + if(!converted && size) state->error = 83; /*alloc fail*/ + if(!state->error) + { + state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); + } + if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); + lodepng_free(converted); + } + else preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); + + ucvector_init(&outv); + while(!state->error) /*while only executed once, to break on error*/ + { +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + size_t i; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*write signature and chunks*/ + writeSignature(&outv); + /*IHDR*/ + addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*unknown chunks between IHDR and PLTE*/ + if(info.unknown_chunks_data[0]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*PLTE*/ + if(info.color.colortype == LCT_PALETTE) + { + addChunk_PLTE(&outv, &info.color); + } + if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) + { + addChunk_PLTE(&outv, &info.color); + } + /*tRNS*/ + if(info.color.colortype == LCT_PALETTE && getPaletteTranslucency(info.color.palette, info.color.palettesize) != 0) + { + addChunk_tRNS(&outv, &info.color); + } + if((info.color.colortype == LCT_GREY || info.color.colortype == LCT_RGB) && info.color.key_defined) + { + addChunk_tRNS(&outv, &info.color); + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*bKGD (must come between PLTE and the IDAt chunks*/ + if(info.background_defined) addChunk_bKGD(&outv, &info); + /*pHYs (must come before the IDAT chunks)*/ + if(info.phys_defined) addChunk_pHYs(&outv, &info); + + /*unknown chunks between PLTE and IDAT*/ + if(info.unknown_chunks_data[1]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*IDAT (multiple IDAT chunks must be consecutive)*/ + state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*tIME*/ + if(info.time_defined) addChunk_tIME(&outv, &info.time); + /*tEXt and/or zTXt*/ + for(i = 0; i < info.text_num; i++) + { + if(strlen(info.text_keys[i]) > 79) + { + state->error = 66; /*text chunk too large*/ + break; + } + if(strlen(info.text_keys[i]) < 1) + { + state->error = 67; /*text chunk too small*/ + break; + } + if(state->encoder.text_compression) + { + addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings); + } + else + { + addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); + } + } + /*LodePNG version id in text chunk*/ + if(state->encoder.add_id) + { + unsigned alread_added_id_text = 0; + for(i = 0; i < info.text_num; i++) + { + if(!strcmp(info.text_keys[i], "LodePNG")) + { + alread_added_id_text = 1; + break; + } + } + if(alread_added_id_text == 0) + { + addChunk_tEXt(&outv, "LodePNG", VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ + } + } + /*iTXt*/ + for(i = 0; i < info.itext_num; i++) + { + if(strlen(info.itext_keys[i]) > 79) + { + state->error = 66; /*text chunk too large*/ + break; + } + if(strlen(info.itext_keys[i]) < 1) + { + state->error = 67; /*text chunk too small*/ + break; + } + addChunk_iTXt(&outv, state->encoder.text_compression, + info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i], + &state->encoder.zlibsettings); + } + + /*unknown chunks between IDAT and IEND*/ + if(info.unknown_chunks_data[2]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + addChunk_IEND(&outv); + + break; /*this isn't really a while loop; no error happened so break out now!*/ + } + + lodepng_info_cleanup(&info); + lodepng_free(data); + /*instead of cleaning the vector up, give it to the output*/ + *out = outv.data; + *outsize = outv.size; + + return state->error; +} + +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, + unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + state.info_png.color.colortype = colortype; + state.info_png.color.bitdepth = bitdepth; + lodepng_encode(out, outsize, image, w, h, &state); + error = state.error; + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth); + if(!error) error = lodepng_save_file(buffer, buffersize, filename); + lodepng_free(buffer); + return error; +} + +unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) +{ + lodepng_compress_settings_init(&settings->zlibsettings); + settings->filter_palette_zero = 1; + settings->filter_strategy = LFS_MINSUM; + settings->auto_convert = 1; + settings->force_palette = 0; + settings->predefined_filters = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->add_id = 0; + settings->text_compression = 1; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/* +This returns the description of a numerical error code in English. This is also +the documentation of all the error codes. +*/ +const char* lodepng_error_text(unsigned code) +{ + switch(code) + { + case 0: return "no error, everything went ok"; + case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/ + case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/ + case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/ + case 13: return "problem while processing dynamic deflate block"; + case 14: return "problem while processing dynamic deflate block"; + case 15: return "problem while processing dynamic deflate block"; + case 16: return "unexisting code while processing dynamic deflate block"; + case 17: return "end of out buffer memory reached while inflating"; + case 18: return "invalid distance code while inflating"; + case 19: return "end of out buffer memory reached while inflating"; + case 20: return "invalid deflate block BTYPE encountered while decoding"; + case 21: return "NLEN is not ones complement of LEN in a deflate block"; + /*end of out buffer memory reached while inflating: + This can happen if the inflated deflate data is longer than the amount of bytes required to fill up + all the pixels of the image, given the color depth and image dimensions. Something that doesn't + happen in a normal, well encoded, PNG image.*/ + case 22: return "end of out buffer memory reached while inflating"; + case 23: return "end of in buffer memory reached while inflating"; + case 24: return "invalid FCHECK in zlib header"; + case 25: return "invalid compression method in zlib header"; + case 26: return "FDICT encountered in zlib header while it's not used for PNG"; + case 27: return "PNG file is smaller than a PNG header"; + /*Checks the magic file header, the first 8 bytes of the PNG file*/ + case 28: return "incorrect PNG signature, it's no PNG or corrupted"; + case 29: return "first chunk is not the header chunk"; + case 30: return "chunk length too large, chunk broken off at end of file"; + case 31: return "illegal PNG color type or bpp"; + case 32: return "illegal PNG compression method"; + case 33: return "illegal PNG filter method"; + case 34: return "illegal PNG interlace method"; + case 35: return "chunk length of a chunk is too large or the chunk too small"; + case 36: return "illegal PNG filter type encountered"; + case 37: return "illegal bit depth for this color type given"; + case 38: return "the palette is too big"; /*more than 256 colors*/ + case 39: return "more palette alpha values given in tRNS chunk than there are colors in the palette"; + case 40: return "tRNS chunk has wrong size for greyscale image"; + case 41: return "tRNS chunk has wrong size for RGB image"; + case 42: return "tRNS chunk appeared while it was not allowed for this color type"; + case 43: return "bKGD chunk has wrong size for palette image"; + case 44: return "bKGD chunk has wrong size for greyscale image"; + case 45: return "bKGD chunk has wrong size for RGB image"; + /*the input data is empty, maybe a PNG file doesn't exist or is in the wrong path*/ + case 48: return "empty input or file doesn't exist"; + case 49: return "jumped past memory while generating dynamic huffman tree"; + case 50: return "jumped past memory while generating dynamic huffman tree"; + case 51: return "jumped past memory while inflating huffman block"; + case 52: return "jumped past memory while inflating"; + case 53: return "size of zlib data too small"; + case 54: return "repeat symbol in tree while there was no value symbol yet"; + /*jumped past tree while generating huffman tree, this could be when the + tree will have more leaves than symbols after generating it out of the + given lenghts. They call this an oversubscribed dynamic bit lengths tree in zlib.*/ + case 55: return "jumped past tree while generating huffman tree"; + case 56: return "given output image colortype or bitdepth not supported for color conversion"; + case 57: return "invalid CRC encountered (checking CRC can be disabled)"; + case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)"; + case 59: return "requested color conversion not supported"; + case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)"; + case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)"; + /*LodePNG leaves the choice of RGB to greyscale conversion formula to the user.*/ + case 62: return "conversion from color to greyscale not supported"; + case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; /*(2^31-1)*/ + /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/ + case 64: return "the length of the END symbol 256 in the Huffman tree is 0"; + case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes"; + case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte"; + case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors"; + case 69: return "unknown chunk type with 'critical' flag encountered by the decoder"; + case 71: return "unexisting interlace mode given to encoder (must be 0 or 1)"; + case 72: return "while decoding, unexisting compression method encountering in zTXt or iTXt chunk (it must be 0)"; + case 73: return "invalid tIME chunk size"; + case 74: return "invalid pHYs chunk size"; + /*length could be wrong, or data chopped off*/ + case 75: return "no null termination char found while decoding text chunk"; + case 76: return "iTXt chunk too short to contain required bytes"; + case 77: return "integer overflow in buffer size"; + case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/ + case 79: return "failed to open file for writing"; + case 80: return "tried creating a tree of 0 symbols"; + case 81: return "lazy matching at pos 0 is impossible"; + case 82: return "color conversion to palette requested while a color isn't in palette"; + case 83: return "memory allocation failed"; + case 84: return "given image too small to contain all pixels to be encoded"; + case 86: return "impossible offset in lz77 encoding (internal bug)"; + case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined"; + case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy"; + case 89: return "text chunk keyword too short or long: must have size 1-79"; + /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/ + case 90: return "windowsize must be a power of two"; + } + return "unknown error code"; +} +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // C++ Wrapper // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng +{ + +#ifdef LODEPNG_COMPILE_DISK +void load_file(std::vector& buffer, const std::string& filename) +{ + std::ifstream file(filename.c_str(), std::ios::in|std::ios::binary|std::ios::ate); + + /*get filesize*/ + std::streamsize size = 0; + if(file.seekg(0, std::ios::end).good()) size = file.tellg(); + if(file.seekg(0, std::ios::beg).good()) size -= file.tellg(); + + /*read contents of the file into the vector*/ + buffer.resize(size_t(size)); + if(size > 0) file.read((char*)(&buffer[0]), size); +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +void save_file(const std::vector& buffer, const std::string& filename) +{ + std::ofstream file(filename.c_str(), std::ios::out|std::ios::binary); + file.write(buffer.empty() ? 0 : (char*)&buffer[0], std::streamsize(buffer.size())); +} +#endif //LODEPNG_COMPILE_DISK + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings) +{ + unsigned char* buffer = 0; + size_t buffersize = 0; + unsigned error = zlib_decompress(&buffer, &buffersize, in, insize, &settings); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned decompress(std::vector& out, const std::vector& in, + const LodePNGDecompressSettings& settings) +{ + return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings); +} +#endif //LODEPNG_COMPILE_DECODER + +#ifdef LODEPNG_COMPILE_ENCODER +unsigned compress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings) +{ + unsigned char* buffer = 0; + size_t buffersize = 0; + unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned compress(std::vector& out, const std::vector& in, + const LodePNGCompressSettings& settings) +{ + return compress(out, in.empty() ? 0 : &in[0], in.size(), settings); +} +#endif //LODEPNG_COMPILE_ENCODER +#endif //LODEPNG_COMPILE_ZLIB + + +#ifdef LODEPNG_COMPILE_PNG + +State::State() +{ + lodepng_state_init(this); +} + +State::State(const State& other) +{ + lodepng_state_init(this); + lodepng_state_copy(this, &other); +} + +State::~State() +{ + lodepng_state_cleanup(this); +} + +State& State::operator=(const State& other) +{ + lodepng_state_copy(this, &other); + return *this; +} + +#ifdef LODEPNG_COMPILE_DECODER + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth); + if(buffer && !error) + { + State state; + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::vector& in, LodePNGColorType colortype, unsigned bitdepth) +{ + return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth); +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize) +{ + unsigned char* buffer = NULL; + unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize); + if(buffer && !error) + { + size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + } + lodepng_free(buffer); + return error; +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const std::vector& in) +{ + return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size()); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename, + LodePNGColorType colortype, unsigned bitdepth) +{ + std::vector buffer; + load_file(buffer, filename); + return decode(out, w, h, buffer, colortype, bitdepth); +} +#endif //LODEPNG_COMPILE_DECODER +#endif //LODEPNG_COMPILE_DISK + +#ifdef LODEPNG_COMPILE_ENCODER +unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); +} + +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + State& state) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + State& state) +{ + if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84; + return encode(out, in.empty() ? 0 : &in[0], w, h, state); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + std::vector buffer; + unsigned error = encode(buffer, in, w, h, colortype, bitdepth); + if(!error) save_file(buffer, filename); + return error; +} + +unsigned encode(const std::string& filename, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); +} +#endif //LODEPNG_COMPILE_DISK +#endif //LODEPNG_COMPILE_ENCODER +#endif //LODEPNG_COMPILE_PNG +} //namespace lodepng +#endif /*LODEPNG_COMPILE_CPP*/ diff --git a/lodepng.h b/lodepng.h new file mode 100644 index 0000000..ef2c820 --- /dev/null +++ b/lodepng.h @@ -0,0 +1,1702 @@ +/* +LodePNG version 20140823 + +Copyright (c) 2005-2014 Lode Vandevenne + +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. +*/ + +#ifndef LODEPNG_H +#define LODEPNG_H + +#include /*for size_t*/ + +#ifdef __cplusplus +#include +#include +#endif /*__cplusplus*/ + +/* +The following #defines are used to create code sections. They can be disabled +to disable code sections, which can give faster compile time and smaller binary. +The "NO_COMPILE" defines are designed to be used to pass as defines to the +compiler command to disable them without modifying this header, e.g. +-DLODEPNG_NO_COMPILE_ZLIB for gcc. +*/ +/*deflate & zlib. If disabled, you must specify alternative zlib functions in +the custom_zlib field of the compress and decompress settings*/ +#ifndef LODEPNG_NO_COMPILE_ZLIB +#define LODEPNG_COMPILE_ZLIB +#endif +/*png encoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_PNG +#define LODEPNG_COMPILE_PNG +#endif +/*deflate&zlib decoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_DECODER +#define LODEPNG_COMPILE_DECODER +#endif +/*deflate&zlib encoder and png encoder*/ +#ifndef LODEPNG_NO_COMPILE_ENCODER +#define LODEPNG_COMPILE_ENCODER +#endif +/*the optional built in harddisk file loading and saving functions*/ +#ifndef LODEPNG_NO_COMPILE_DISK +#define LODEPNG_COMPILE_DISK +#endif +/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ +#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS +#define LODEPNG_COMPILE_ANCILLARY_CHUNKS +#endif +/*ability to convert error numerical codes to English text string*/ +#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT +#define LODEPNG_COMPILE_ERROR_TEXT +#endif +/*Compile the default allocators (C's free, malloc and realloc). If you disable this, +you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your +source files with custom allocators.*/ +#ifndef LODEPNG_NO_COMPILE_ALLOCATORS +#define LODEPNG_COMPILE_ALLOCATORS +#endif +/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ +#ifdef __cplusplus +#ifndef LODEPNG_NO_COMPILE_CPP +#define LODEPNG_COMPILE_CPP +#endif +#endif + +#ifdef LODEPNG_COMPILE_PNG +/*The PNG color types (also used for raw).*/ +typedef enum LodePNGColorType +{ + LCT_GREY = 0, /*greyscale: 1,2,4,8,16 bit*/ + LCT_RGB = 2, /*RGB: 8,16 bit*/ + LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ + LCT_GREY_ALPHA = 4, /*greyscale with alpha: 8,16 bit*/ + LCT_RGBA = 6 /*RGB with alpha: 8,16 bit*/ +} LodePNGColorType; + +#ifdef LODEPNG_COMPILE_DECODER +/* +Converts PNG data in memory to raw pixel data. +out: Output parameter. Pointer to buffer that will contain the raw pixel data. + After decoding, its size is w * h * (bytes per pixel) bytes larger than + initially. Bytes per pixel depends on colortype and bitdepth. + Must be freed after usage with free(*out). + Note: for 16-bit per channel colors, uses big endian format like PNG does. +w: Output parameter. Pointer to width of pixel data. +h: Output parameter. Pointer to height of pixel data. +in: Memory buffer with the PNG file. +insize: size of the in buffer. +colortype: the desired color type for the raw output image. See explanation on PNG color types. +bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +/*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +#ifdef LODEPNG_COMPILE_DISK +/* +Load PNG from disk, from file with given name. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/ +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); + +/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/ +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Converts raw pixel data into a PNG image in memory. The colortype and bitdepth + of the output PNG image cannot be chosen, they are automatically determined + by the colortype, bitdepth and content of the input pixel data. + Note: for 16-bit per channel colors, needs big endian format like PNG does. +out: Output parameter. Pointer to buffer that will contain the PNG image data. + Must be freed after usage with free(*out). +outsize: Output parameter. Pointer to the size in bytes of the out buffer. +image: The raw pixel data to encode. The size of this buffer should be + w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. +w: width of the raw pixel data in pixels. +h: height of the raw pixel data in pixels. +colortype: the color type of the raw input image. See explanation on PNG color types. +bitdepth: the bit depth of the raw input image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DISK +/* +Converts raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned lodepng_encode_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng +{ +#ifdef LODEPNG_COMPILE_DECODER +/*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype +is the format to output the pixels to. Default is RGBA 8-bit per channel.*/ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::vector& in, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts PNG file from disk to raw pixel data in memory. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::string& filename, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif //LODEPNG_COMPILE_DISK +#endif //LODEPNG_COMPILE_DECODER + +#ifdef LODEPNG_COMPILE_ENCODER +/*Same as lodepng_encode_memory, but encodes to an std::vector. colortype +is that of the raw input data. The output PNG color type will be auto chosen.*/ +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts 32-bit RGBA raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(const std::string& filename, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif //LODEPNG_COMPILE_DISK +#endif //LODEPNG_COMPILE_ENCODER +} //namespace lodepng +#endif /*LODEPNG_COMPILE_CPP*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/*Returns an English description of the numerical error code.*/ +const char* lodepng_error_text(unsigned code); +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Settings for zlib decompression*/ +typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; +struct LodePNGDecompressSettings +{ + unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ + + /*use custom zlib decoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + /*use custom deflate decoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_inflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGDecompressSettings lodepng_default_decompress_settings; +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Settings for zlib compression. Tweaking these settings tweaks the balance +between speed and compression ratio. +*/ +typedef struct LodePNGCompressSettings LodePNGCompressSettings; +struct LodePNGCompressSettings /*deflate = compress*/ +{ + /*LZ77 related settings*/ + unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ + unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ + unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ + unsigned minmatch; /*mininum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ + unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ + unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ + + /*use custom zlib encoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + /*use custom deflate encoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_deflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGCompressSettings lodepng_default_compress_settings; +void lodepng_compress_settings_init(LodePNGCompressSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_PNG +/* +Color mode of an image. Contains all information required to decode the pixel +bits to RGBA colors. This information is the same as used in the PNG file +format, and is used both for PNG and raw image data in LodePNG. +*/ +typedef struct LodePNGColorMode +{ + /*header (IHDR)*/ + LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ + unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ + + /* + palette (PLTE and tRNS) + + Dynamically allocated with the colors of the palette, including alpha. + When encoding a PNG, to store your colors in the palette of the LodePNGColorMode, first use + lodepng_palette_clear, then for each color use lodepng_palette_add. + If you encode an image without alpha with palette, don't forget to put value 255 in each A byte of the palette. + + When decoding, by default you can ignore this palette, since LodePNG already + fills the palette colors in the pixels of the raw RGBA output. + + The palette is only supported for color type 3. + */ + unsigned char* palette; /*palette in RGBARGBA... order. When allocated, must be either 0, or have size 1024*/ + size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/ + + /* + transparent color key (tRNS) + + This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. + For greyscale PNGs, r, g and b will all 3 be set to the same. + + When decoding, by default you can ignore this information, since LodePNG sets + pixels with this key to transparent already in the raw RGBA output. + + The color key is only supported for color types 0 and 2. + */ + unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ + unsigned key_r; /*red/greyscale component of color key*/ + unsigned key_g; /*green component of color key*/ + unsigned key_b; /*blue component of color key*/ +} LodePNGColorMode; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_color_mode_init(LodePNGColorMode* info); +void lodepng_color_mode_cleanup(LodePNGColorMode* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); + +void lodepng_palette_clear(LodePNGColorMode* info); +/*add 1 color to the palette*/ +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +/*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ +unsigned lodepng_get_bpp(const LodePNGColorMode* info); +/*get the amount of color channels used, based on colortype in the struct. +If a palette is used, it counts as 1 channel.*/ +unsigned lodepng_get_channels(const LodePNGColorMode* info); +/*is it a greyscale type? (only colortype 0 or 4)*/ +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); +/*has it got an alpha channel? (only colortype 2 or 6)*/ +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); +/*has it got a palette? (only colortype 3)*/ +unsigned lodepng_is_palette_type(const LodePNGColorMode* info); +/*only returns true if there is a palette and there is a value in the palette with alpha < 255. +Loops through the palette to check this.*/ +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); +/* +Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. +Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). +Returns false if the image can only have opaque pixels. +In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, +or if "key_defined" is true. +*/ +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); +/*Returns the byte size of a raw image buffer with given width, height and color mode*/ +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*The information of a Time chunk in PNG.*/ +typedef struct LodePNGTime +{ + unsigned year; /*2 bytes used (0-65535)*/ + unsigned month; /*1-12*/ + unsigned day; /*1-31*/ + unsigned hour; /*0-23*/ + unsigned minute; /*0-59*/ + unsigned second; /*0-60 (to allow for leap seconds)*/ +} LodePNGTime; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*Information about the PNG image, except pixels, width and height.*/ +typedef struct LodePNGInfo +{ + /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ + unsigned compression_method;/*compression method of the original file. Always 0.*/ + unsigned filter_method; /*filter method of the original file*/ + unsigned interlace_method; /*interlace method of the original file*/ + LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /* + suggested background color chunk (bKGD) + This color uses the same color mode as the PNG (except alpha channel), which can be 1-bit to 16-bit. + + For greyscale PNGs, r, g and b will all 3 be set to the same. When encoding + the encoder writes the red one. For palette PNGs: When decoding, the RGB value + will be stored, not a palette index. But when encoding, specify the index of + the palette in background_r, the other two are then ignored. + + The decoder does not use this background color to edit the color of pixels. + */ + unsigned background_defined; /*is a suggested background color given?*/ + unsigned background_r; /*red component of suggested background color*/ + unsigned background_g; /*green component of suggested background color*/ + unsigned background_b; /*blue component of suggested background color*/ + + /* + non-international text chunks (tEXt and zTXt) + + The char** arrays each contain num strings. The actual messages are in + text_strings, while text_keys are keywords that give a short description what + the actual text represents, e.g. Title, Author, Description, or anything else. + + A keyword is minimum 1 character and maximum 79 characters long. It's + discouraged to use a single line length longer than 79 characters for texts. + + Don't allocate these text buffers yourself. Use the init/cleanup functions + correctly and use lodepng_add_text and lodepng_clear_text. + */ + size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ + char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ + char** text_strings; /*the actual text*/ + + /* + international text chunks (iTXt) + Similar to the non-international text chunks, but with additional strings + "langtags" and "transkeys". + */ + size_t itext_num; /*the amount of international texts in this PNG*/ + char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ + char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ + char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ + char** itext_strings; /*the actual international text - UTF-8 string*/ + + /*time chunk (tIME)*/ + unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ + LodePNGTime time; + + /*phys chunk (pHYs)*/ + unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ + unsigned phys_x; /*pixels per unit in x direction*/ + unsigned phys_y; /*pixels per unit in y direction*/ + unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ + + /* + unknown chunks + There are 3 buffers, one for each position in the PNG where unknown chunks can appear + each buffer contains all unknown chunks for that position consecutively + The 3 buffers are the unknown chunks between certain critical chunks: + 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND + Do not allocate or traverse this data yourself. Use the chunk traversing functions declared + later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. + */ + unsigned char* unknown_chunks_data[3]; + size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGInfo; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_info_init(LodePNGInfo* info); +void lodepng_info_cleanup(LodePNGInfo* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ + +void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/* +Converts raw buffer from one color type to another color type, based on +LodePNGColorMode structs to describe the input and output color type. +See the reference manual at the end of this header file to see which color conversions are supported. +return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) +The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel +of the output color type (lodepng_get_bpp). +For < 8 bpp images, there should not be padding bits at the end of scanlines. +For 16-bit per channel colors, uses big endian format like PNG does. +Return value is LodePNG error code +*/ +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DECODER +/* +Settings for the decoder. This contains settings for the PNG and the Zlib +decoder, but not the Info settings from the Info structs. +*/ +typedef struct LodePNGDecoderSettings +{ + LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ + + unsigned ignore_crc; /*ignore CRC checksums*/ + + unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ + /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ + unsigned remember_unknown_chunks; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGDecoderSettings; + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ +typedef enum LodePNGFilterStrategy +{ + /*every filter at zero*/ + LFS_ZERO, + /*Use filter that gives minumum sum, as described in the official PNG filter heuristic.*/ + LFS_MINSUM, + /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending + on the image, this is better or worse than minsum.*/ + LFS_ENTROPY, + /* + Brute-force-search PNG filters by compressing each filter for each scanline. + Experimental, very slow, and only rarely gives better compression than MINSUM. + */ + LFS_BRUTE_FORCE, + /*use predefined_filters buffer: you specify the filter type for each scanline*/ + LFS_PREDEFINED +} LodePNGFilterStrategy; + +/*Gives characteristics about the colors of the image, which helps decide which color model to use for encoding. +Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/ +typedef struct LodePNGColorProfile +{ + unsigned colored; /*not greyscale*/ + unsigned key; /*if true, image is not opaque. Only if true and alpha is false, color key is possible.*/ + unsigned short key_r; /*these values are always in 16-bit bitdepth in the profile*/ + unsigned short key_g; + unsigned short key_b; + unsigned alpha; /*alpha channel or alpha palette required*/ + unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16.*/ + unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order*/ + unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for greyscale only. 16 if 16-bit per channel required.*/ +} LodePNGColorProfile; + +void lodepng_color_profile_init(LodePNGColorProfile* profile); + +/*Get a LodePNGColorProfile of the image.*/ +unsigned get_color_profile(LodePNGColorProfile* profile, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in); +/*The function LodePNG uses internally to decide the PNG color with auto_convert. +Chooses an optimal color model, e.g. grey if only grey pixels, palette if < 256 colors, ...*/ +unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in); + +/*Settings for the encoder.*/ +typedef struct LodePNGEncoderSettings +{ + LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ + + unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/ + + /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than + 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to + completely follow the official PNG heuristic, filter_palette_zero must be true and + filter_strategy must be LFS_MINSUM*/ + unsigned filter_palette_zero; + /*Which filter strategy to use when not using zeroes due to filter_palette_zero. + Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ + LodePNGFilterStrategy filter_strategy; + /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with + the same length as the amount of scanlines in the image, and each value must <= 5. You + have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero + must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ + const unsigned char* predefined_filters; + + /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). + If colortype is 3, PLTE is _always_ created.*/ + unsigned force_palette; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*add LodePNG identifier and version as a text chunk, for debugging*/ + unsigned add_id; + /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ + unsigned text_compression; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGEncoderSettings; + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) +/*The settings, state and information for extended encoding and decoding.*/ +typedef struct LodePNGState +{ +#ifdef LODEPNG_COMPILE_DECODER + LodePNGDecoderSettings decoder; /*the decoding settings*/ +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + LodePNGEncoderSettings encoder; /*the encoding settings*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ + LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ + unsigned error; +#ifdef LODEPNG_COMPILE_CPP + //For the lodepng::State subclass. + virtual ~LodePNGState(){} +#endif +} LodePNGState; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_state_init(LodePNGState* state); +void lodepng_state_cleanup(LodePNGState* state); +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_DECODER +/* +Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and +getting much more information about the PNG image and color mode. +*/ +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); + +/* +Read the PNG header, but not the actual data. This returns only the information +that is in the header chunk of the PNG, such as width, height and color type. The +information is placed in the info_png field of the LodePNGState. +*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* +The lodepng_chunk functions are normally not needed, except to traverse the +unknown chunks stored in the LodePNGInfo struct, or add new ones to it. +It also allows traversing the chunks of an encoded PNG file yourself. + +PNG standard chunk naming conventions: +First byte: uppercase = critical, lowercase = ancillary +Second byte: uppercase = public, lowercase = private +Third byte: must be uppercase +Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy +*/ + +/*get the length of the data of the chunk. Total chunk length has 12 bytes more.*/ +unsigned lodepng_chunk_length(const unsigned char* chunk); + +/*puts the 4-byte type in null terminated string*/ +void lodepng_chunk_type(char type[5], const unsigned char* chunk); + +/*check if the type is the given type*/ +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); + +/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); + +/*0: public, 1: private (see PNG standard)*/ +unsigned char lodepng_chunk_private(const unsigned char* chunk); + +/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); + +/*get pointer to the data of the chunk, where the input points to the header of the chunk*/ +unsigned char* lodepng_chunk_data(unsigned char* chunk); +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); + +/*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ +unsigned lodepng_chunk_check_crc(const unsigned char* chunk); + +/*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ +void lodepng_chunk_generate_crc(unsigned char* chunk); + +/*iterate to next chunks. don't use on IEND chunk, as there is no next chunk then*/ +unsigned char* lodepng_chunk_next(unsigned char* chunk); +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk); + +/* +Appends chunk to the data in out. The given chunk should already have its chunk header. +The out variable and outlength are updated to reflect the new reallocated buffer. +Returns error code (0 if it went ok) +*/ +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk); + +/* +Appends new chunk to out. The chunk to append is given by giving its length, type +and data separately. The type is a 4-letter string. +The out variable and outlength are updated to reflect the new reallocated buffer. +Returne error code (0 if it went ok) +*/ +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data); + + +/*Calculate CRC32 of buffer*/ +unsigned lodepng_crc32(const unsigned char* buf, size_t len); +#endif /*LODEPNG_COMPILE_PNG*/ + + +#ifdef LODEPNG_COMPILE_ZLIB +/* +This zlib part can be used independently to zlib compress and decompress a +buffer. It cannot be used to create gzip files however, and it only supports the +part of zlib that is required for PNG, it does not support dictionaries. +*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); + +/* +Decompresses Zlib data. Reallocates the out buffer and appends the data. The +data must be according to the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Compresses data with Zlib. Reallocates the out buffer and appends the data. +Zlib adds a small header and trailer around the deflate data. +The data is output in the format of the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +/* +Find length-limited Huffman code for given frequencies. This function is in the +public interface only for tests, it's used internally by lodepng_deflate. +*/ +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen); + +/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into buffer. The function allocates the out buffer, and +after usage you should free it. +out: output parameter, contains pointer to loaded buffer. +outsize: output parameter, size of the allocated out buffer +filename: the path to the file to load +return value: error code (0 means ok) +*/ +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); + +/* +Save a file from buffer to disk. Warning, if it exists, this function overwrites +the file without warning! +buffer: the buffer to write +buffersize: size of the buffer to write +filename: the path to the file to save to +return value: error code (0 means ok) +*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ + +#ifdef LODEPNG_COMPILE_CPP +//The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. +namespace lodepng +{ +#ifdef LODEPNG_COMPILE_PNG +class State : public LodePNGState +{ + public: + State(); + State(const State& other); + virtual ~State(); + State& operator=(const State& other); +}; + +#ifdef LODEPNG_COMPILE_DECODER +//Same as other lodepng::decode, but using a State for more settings and information. +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize); +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const std::vector& in); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +//Same as other lodepng::encode, but using a State for more settings and information. +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + State& state); +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + State& state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into an std::vector. If the vector is empty, then either +the file doesn't exist or is an empty file. +*/ +void load_file(std::vector& buffer, const std::string& filename); + +/* +Save the binary data in an std::vector to a file on disk. The file is overwritten +without warning. +*/ +void save_file(const std::vector& buffer, const std::string& filename); +#endif //LODEPNG_COMPILE_DISK +#endif //LODEPNG_COMPILE_PNG + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +//Zlib-decompress an unsigned char buffer +unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); + +//Zlib-decompress an std::vector +unsigned decompress(std::vector& out, const std::vector& in, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); +#endif //LODEPNG_COMPILE_DECODER + +#ifdef LODEPNG_COMPILE_ENCODER +//Zlib-compress an unsigned char buffer +unsigned compress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); + +//Zlib-compress an std::vector +unsigned compress(std::vector& out, const std::vector& in, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); +#endif //LODEPNG_COMPILE_ENCODER +#endif //LODEPNG_COMPILE_ZLIB +} //namespace lodepng +#endif /*LODEPNG_COMPILE_CPP*/ + +/* +TODO: +[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often +[.] check compatibility with vareous compilers - done but needs to be redone for every newer version +[X] converting color to 16-bit per channel types +[ ] read all public PNG chunk types (but never let the color profile and gamma ones touch RGB values) +[ ] make sure encoder generates no chunks with size > (2^31)-1 +[ ] partial decoding (stream processing) +[X] let the "isFullyOpaque" function check color keys and transparent palettes too +[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" +[ ] don't stop decoding on errors like 69, 57, 58 (make warnings) +[ ] make option to choose if the raw image with non multiple of 8 bits per scanline should have padding bits or not +[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes +*/ + +#endif /*LODEPNG_H inclusion guard*/ + +/* +LodePNG Documentation +--------------------- + +0. table of contents +-------------------- + + 1. about + 1.1. supported features + 1.2. features not supported + 2. C and C++ version + 3. security + 4. decoding + 5. encoding + 6. color conversions + 6.1. PNG color types + 6.2. color conversions + 6.3. padding bits + 6.4. A note about 16-bits per channel and endianness + 7. error values + 8. chunks and PNG editing + 9. compiler support + 10. examples + 10.1. decoder C++ example + 10.2. decoder C example + 11. changes + 12. contact information + + +1. about +-------- + +PNG is a file format to store raster images losslessly with good compression, +supporting different color types and alpha channel. + +LodePNG is a PNG codec according to the Portable Network Graphics (PNG) +Specification (Second Edition) - W3C Recommendation 10 November 2003. + +The specifications used are: + +*) Portable Network Graphics (PNG) Specification (Second Edition): + http://www.w3.org/TR/2003/REC-PNG-20031110 +*) RFC 1950 ZLIB Compressed Data Format version 3.3: + http://www.gzip.org/zlib/rfc-zlib.html +*) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: + http://www.gzip.org/zlib/rfc-deflate.html + +The most recent version of LodePNG can currently be found at +http://lodev.org/lodepng/ + +LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds +extra functionality. + +LodePNG exists out of two files: +-lodepng.h: the header file for both C and C++ +-lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage + +If you want to start using LodePNG right away without reading this doc, get the +examples from the LodePNG website to see how to use it in code, or check the +smaller examples in chapter 13 here. + +LodePNG is simple but only supports the basic requirements. To achieve +simplicity, the following design choices were made: There are no dependencies +on any external library. There are functions to decode and encode a PNG with +a single function call, and extended versions of these functions taking a +LodePNGState struct allowing to specify or get more information. By default +the colors of the raw image are always RGB or RGBA, no matter what color type +the PNG file uses. To read and write files, there are simple functions to +convert the files to/from buffers in memory. + +This all makes LodePNG suitable for loading textures in games, demos and small +programs, ... It's less suitable for full fledged image editors, loading PNGs +over network (it requires all the image data to be available before decoding can +begin), life-critical systems, ... + +1.1. supported features +----------------------- + +The following features are supported by the decoder: + +*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, + or the same color type as the PNG +*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image +*) Adam7 interlace and deinterlace for any color type +*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk +*) support for alpha channels, including RGBA color model, translucent palettes and color keying +*) zlib decompression (inflate) +*) zlib compression (deflate) +*) CRC32 and ADLER32 checksums +*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. +*) the following chunks are supported (generated/interpreted) by both encoder and decoder: + IHDR: header information + PLTE: color palette + IDAT: pixel data + IEND: the final chunk + tRNS: transparency for palettized images + tEXt: textual information + zTXt: compressed textual information + iTXt: international textual information + bKGD: suggested background color + pHYs: physical dimensions + tIME: modification time + +1.2. features not supported +--------------------------- + +The following features are _not_ supported: + +*) some features needed to make a conformant PNG-Editor might be still missing. +*) partial loading/stream processing. All data must be available and is processed in one call. +*) The following public chunks are not supported but treated as unknown chunks by LodePNG + cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT + Some of these are not supported on purpose: LodePNG wants to provide the RGB values + stored in the pixels, not values modified by system dependent gamma or color models. + + +2. C and C++ version +-------------------- + +The C version uses buffers allocated with alloc that you need to free() +yourself. You need to use init and cleanup functions for each struct whenever +using a struct from the C version to avoid exploits and memory leaks. + +The C++ version has extra functions with std::vectors in the interface and the +lodepng::State class which is a LodePNGState with constructor and destructor. + +These files work without modification for both C and C++ compilers because all +the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers +ignore it, and the C code is made to compile both with strict ISO C90 and C++. + +To use the C++ version, you need to rename the source file to lodepng.cpp +(instead of lodepng.c), and compile it with a C++ compiler. + +To use the C version, you need to rename the source file to lodepng.c (instead +of lodepng.cpp), and compile it with a C compiler. + + +3. Security +----------- + +Even if carefully designed, it's always possible that LodePNG contains possible +exploits. If you discover one, please let me know, and it will be fixed. + +When using LodePNG, care has to be taken with the C version of LodePNG, as well +as the C-style structs when working with C++. The following conventions are used +for all C-style structs: + +-if a struct has a corresponding init function, always call the init function when making a new one +-if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks +-if a struct has a corresponding copy function, use the copy function instead of "=". + The destination must also be inited already. + + +4. Decoding +----------- + +Decoding converts a PNG compressed image to a raw pixel buffer. + +Most documentation on using the decoder is at its declarations in the header +above. For C, simple decoding can be done with functions such as +lodepng_decode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_decode. For C++, all decoding can be done with the +various lodepng::decode functions, and lodepng::State can be used for advanced +features. + +When using the LodePNGState, it uses the following fields for decoding: +*) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here +*) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get +*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use + +LodePNGInfo info_png +-------------------- + +After decoding, this contains extra information of the PNG image, except the actual +pixels, width and height because these are already gotten directly from the decoder +functions. + +It contains for example the original color type of the PNG image, text comments, +suggested background color, etc... More details about the LodePNGInfo struct are +at its declaration documentation. + +LodePNGColorMode info_raw +------------------------- + +When decoding, here you can specify which color type you want +the resulting raw image to be. If this is different from the colortype of the +PNG, then the decoder will automatically convert the result. This conversion +always works, except if you want it to convert a color PNG to greyscale or to +a palette with missing colors. + +By default, 32-bit color is used for the result. + +LodePNGDecoderSettings decoder +------------------------------ + +The settings can be used to ignore the errors created by invalid CRC and Adler32 +chunks, and to disable the decoding of tEXt chunks. + +There's also a setting color_convert, true by default. If false, no conversion +is done, the resulting data will be as it was in the PNG (after decompression) +and you'll have to puzzle the colors of the pixels together yourself using the +color type information in the LodePNGInfo. + + +5. Encoding +----------- + +Encoding converts a raw pixel buffer to a PNG compressed image. + +Most documentation on using the encoder is at its declarations in the header +above. For C, simple encoding can be done with functions such as +lodepng_encode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_encode. For C++, all encoding can be done with the +various lodepng::encode functions, and lodepng::State can be used for advanced +features. + +Like the decoder, the encoder can also give errors. However it gives less errors +since the encoder input is trusted, the decoder input (a PNG image that could +be forged by anyone) is not trusted. + +When using the LodePNGState, it uses the following fields for encoding: +*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. +*) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has +*) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use + +LodePNGInfo info_png +-------------------- + +When encoding, you use this the opposite way as when decoding: for encoding, +you fill in the values you want the PNG to have before encoding. By default it's +not needed to specify a color type for the PNG since it's automatically chosen, +but it's possible to choose it yourself given the right settings. + +The encoder will not always exactly match the LodePNGInfo struct you give, +it tries as close as possible. Some things are ignored by the encoder. The +encoder uses, for example, the following settings from it when applicable: +colortype and bitdepth, text chunks, time chunk, the color key, the palette, the +background color, the interlace method, unknown chunks, ... + +When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. +If the palette contains any colors for which the alpha channel is not 255 (so +there are translucent colors in the palette), it'll add a tRNS chunk. + +LodePNGColorMode info_raw +------------------------- + +You specify the color type of the raw image that you give to the input here, +including a possible transparent color key and palette you happen to be using in +your raw image data. + +By default, 32-bit color is assumed, meaning your input has to be in RGBA +format with 4 bytes (unsigned chars) per pixel. + +LodePNGEncoderSettings encoder +------------------------------ + +The following settings are supported (some are in sub-structs): +*) auto_convert: when this option is enabled, the encoder will +automatically choose the smallest possible color mode (including color key) that +can encode the colors of all pixels without information loss. +*) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, + 2 = dynamic huffman tree (best compression). Should be 2 for proper + compression. +*) use_lz77: whether or not to use LZ77 for compressed block types. Should be + true for proper compression. +*) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value + 2048 by default, but can be set to 32768 for better, but slow, compression. +*) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE + chunk if force_palette is true. This can used as suggested palette to convert + to by viewers that don't support more than 256 colors (if those still exist) +*) add_id: add text chunk "Encoder: LodePNG " to the image. +*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. + zTXt chunks use zlib compression on the text. This gives a smaller result on + large texts but a larger result on small texts (such as a single program name). + It's all tEXt or all zTXt though, there's no separate setting per text yet. + + +6. color conversions +-------------------- + +An important thing to note about LodePNG, is that the color type of the PNG, and +the color type of the raw image, are completely independent. By default, when +you decode a PNG, you get the result as a raw image in the color type you want, +no matter whether the PNG was encoded with a palette, greyscale or RGBA color. +And if you encode an image, by default LodePNG will automatically choose the PNG +color type that gives good compression based on the values of colors and amount +of colors in the image. It can be configured to let you control it instead as +well, though. + +To be able to do this, LodePNG does conversions from one color mode to another. +It can convert from almost any color type to any other color type, except the +following conversions: RGB to greyscale is not supported, and converting to a +palette when the palette doesn't have a required color is not supported. This is +not supported on purpose: this is information loss which requires a color +reduction algorithm that is beyong the scope of a PNG encoder (yes, RGB to grey +is easy, but there are multiple ways if you want to give some channels more +weight). + +By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB +color, no matter what color type the PNG has. And by default when encoding, +LodePNG automatically picks the best color model for the output PNG, and expects +the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control +the color format of the images yourself, you can skip this chapter. + +6.1. PNG color types +-------------------- + +A PNG image can have many color types, ranging from 1-bit color to 64-bit color, +as well as palettized color modes. After the zlib decompression and unfiltering +in the PNG image is done, the raw pixel data will have that color type and thus +a certain amount of bits per pixel. If you want the output raw image after +decoding to have another color type, a conversion is done by LodePNG. + +The PNG specification gives the following color types: + +0: greyscale, bit depths 1, 2, 4, 8, 16 +2: RGB, bit depths 8 and 16 +3: palette, bit depths 1, 2, 4 and 8 +4: greyscale with alpha, bit depths 8 and 16 +6: RGBA, bit depths 8 and 16 + +Bit depth is the amount of bits per pixel per color channel. So the total amount +of bits per pixel is: amount of channels * bitdepth. + +6.2. color conversions +---------------------- + +As explained in the sections about the encoder and decoder, you can specify +color types and bit depths in info_png and info_raw to change the default +behaviour. + +If, when decoding, you want the raw image to be something else than the default, +you need to set the color type and bit depth you want in the LodePNGColorMode, +or the parameters colortype and bitdepth of the simple decoding function. + +If, when encoding, you use another color type than the default in the raw input +image, you need to specify its color type and bit depth in the LodePNGColorMode +of the raw image, or use the parameters colortype and bitdepth of the simple +encoding function. + +If, when encoding, you don't want LodePNG to choose the output PNG color type +but control it yourself, you need to set auto_convert in the encoder settings +to false, and specify the color type you want in the LodePNGInfo of the +encoder (including palette: it can generate a palette if auto_convert is true, +otherwise not). + +If the input and output color type differ (whether user chosen or auto chosen), +LodePNG will do a color conversion, which follows the rules below, and may +sometimes result in an error. + +To avoid some confusion: +-the decoder converts from PNG to raw image +-the encoder converts from raw image to PNG +-the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image +-the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG +-when encoding, the color type in LodePNGInfo is ignored if auto_convert + is enabled, it is automatically generated instead +-when decoding, the color type in LodePNGInfo is set by the decoder to that of the original + PNG image, but it can be ignored since the raw image has the color type you requested instead +-if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion + between the color types is done if the color types are supported. If it is not + supported, an error is returned. If the types are the same, no conversion is done. +-even though some conversions aren't supported, LodePNG supports loading PNGs from any + colortype and saving PNGs to any colortype, sometimes it just requires preparing + the raw image correctly before encoding. +-both encoder and decoder use the same color converter. + +Non supported color conversions: +-color to greyscale: no error is thrown, but the result will look ugly because +only the red channel is taken +-anything to palette when that palette does not have that color in it: in this +case an error is thrown + +Supported color conversions: +-anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA +-any grey or grey+alpha, to grey or grey+alpha +-anything to a palette, as long as the palette has the requested colors in it +-removing alpha channel +-higher to smaller bitdepth, and vice versa + +If you want no color conversion to be done (e.g. for speed or control): +-In the encoder, you can make it save a PNG with any color type by giving the +raw color mode and LodePNGInfo the same color mode, and setting auto_convert to +false. +-In the decoder, you can make it store the pixel data in the same color type +as the PNG has, by setting the color_convert setting to false. Settings in +info_raw are then ignored. + +The function lodepng_convert does the color conversion. It is available in the +interface but normally isn't needed since the encoder and decoder already call +it. + +6.3. padding bits +----------------- + +In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines +have a bit amount that isn't a multiple of 8, then padding bits are used so that each +scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. +The raw input image you give to the encoder, and the raw output image you get from the decoder +will NOT have these padding bits, e.g. in the case of a 1-bit image with a width +of 7 pixels, the first pixel of the second scanline will the the 8th bit of the first byte, +not the first bit of a new byte. + +6.4. A note about 16-bits per channel and endianness +---------------------------------------------------- + +LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like +for any other color format. The 16-bit values are stored in big endian (most +significant byte first) in these arrays. This is the opposite order of the +little endian used by x86 CPU's. + +LodePNG always uses big endian because the PNG file format does so internally. +Conversions to other formats than PNG uses internally are not supported by +LodePNG on purpose, there are myriads of formats, including endianness of 16-bit +colors, the order in which you store R, G, B and A, and so on. Supporting and +converting to/from all that is outside the scope of LodePNG. + +This may mean that, depending on your use case, you may want to convert the big +endian output of LodePNG to little endian with a for loop. This is certainly not +always needed, many applications and libraries support big endian 16-bit colors +anyway, but it means you cannot simply cast the unsigned char* buffer to an +unsigned short* buffer on x86 CPUs. + + +7. error values +--------------- + +All functions in LodePNG that return an error code, return 0 if everything went +OK, or a non-zero code if there was an error. + +The meaning of the LodePNG error values can be retrieved with the function +lodepng_error_text: given the numerical error code, it returns a description +of the error in English as a string. + +Check the implementation of lodepng_error_text to see the meaning of each code. + + +8. chunks and PNG editing +------------------------- + +If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG +editor that should follow the rules about handling of unknown chunks, or if your +program is able to read other types of chunks than the ones handled by LodePNG, +then that's possible with the chunk functions of LodePNG. + +A PNG chunk has the following layout: + +4 bytes length +4 bytes type name +length bytes data +4 bytes CRC + +8.1. iterating through chunks +----------------------------- + +If you have a buffer containing the PNG image data, then the first chunk (the +IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the +signature of the PNG and are not part of a chunk. But if you start at byte 8 +then you have a chunk, and can check the following things of it. + +NOTE: none of these functions check for memory buffer boundaries. To avoid +exploits, always make sure the buffer contains all the data of the chunks. +When using lodepng_chunk_next, make sure the returned value is within the +allocated memory. + +unsigned lodepng_chunk_length(const unsigned char* chunk): + +Get the length of the chunk's data. The total chunk length is this length + 12. + +void lodepng_chunk_type(char type[5], const unsigned char* chunk): +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): + +Get the type of the chunk or compare if it's a certain type + +unsigned char lodepng_chunk_critical(const unsigned char* chunk): +unsigned char lodepng_chunk_private(const unsigned char* chunk): +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): + +Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). +Check if the chunk is private (public chunks are part of the standard, private ones not). +Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical +chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your +program doesn't handle that type of unknown chunk. + +unsigned char* lodepng_chunk_data(unsigned char* chunk): +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): + +Get a pointer to the start of the data of the chunk. + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk): +void lodepng_chunk_generate_crc(unsigned char* chunk): + +Check if the crc is correct or generate a correct one. + +unsigned char* lodepng_chunk_next(unsigned char* chunk): +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): + +Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these +functions do no boundary checking of the allocated data whatsoever, so make sure there is enough +data available in the buffer to be able to go to the next chunk. + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk): +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data): + +These functions are used to create new chunks that are appended to the data in *out that has +length *outlength. The append function appends an existing chunk to the new data. The create +function creates a new chunk with the given parameters and appends it. Type is the 4-letter +name of the chunk. + +8.2. chunks in info_png +----------------------- + +The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 +buffers (each with size) to contain 3 types of unknown chunks: +the ones that come before the PLTE chunk, the ones that come between the PLTE +and the IDAT chunks, and the ones that come after the IDAT chunks. +It's necessary to make the distionction between these 3 cases because the PNG +standard forces to keep the ordering of unknown chunks compared to the critical +chunks, but does not force any other ordering rules. + +info_png.unknown_chunks_data[0] is the chunks before PLTE +info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT +info_png.unknown_chunks_data[2] is the chunks after IDAT + +The chunks in these 3 buffers can be iterated through and read by using the same +way described in the previous subchapter. + +When using the decoder to decode a PNG, you can make it store all unknown chunks +if you set the option settings.remember_unknown_chunks to 1. By default, this +option is off (0). + +The encoder will always encode unknown chunks that are stored in the info_png. +If you need it to add a particular chunk that isn't known by LodePNG, you can +use lodepng_chunk_append or lodepng_chunk_create to the chunk data in +info_png.unknown_chunks_data[x]. + +Chunks that are known by LodePNG should not be added in that way. E.g. to make +LodePNG add a bKGD chunk, set background_defined to true and add the correct +parameters there instead. + + +9. compiler support +------------------- + +No libraries other than the current standard C library are needed to compile +LodePNG. For the C++ version, only the standard C++ library is needed on top. +Add the files lodepng.c(pp) and lodepng.h to your project, include +lodepng.h where needed, and your program can read/write PNG files. + +It is compatible with C90 and up, and C++03 and up. + +If performance is important, use optimization when compiling! For both the +encoder and decoder, this makes a large difference. + +Make sure that LodePNG is compiled with the same compiler of the same version +and with the same settings as the rest of the program, or the interfaces with +std::vectors and std::strings in C++ can be incompatible. + +CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. + +*) gcc and g++ + +LodePNG is developed in gcc so this compiler is natively supported. It gives no +warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ +version 4.7.1 on Linux, 32-bit and 64-bit. + +*) Clang + +Fully supported and warning-free. + +*) Mingw + +The Mingw compiler (a port of gcc for Windows) should be fully supported by +LodePNG. + +*) Visual Studio and Visual C++ Express Edition + +LodePNG should be warning-free with warning level W4. Two warnings were disabled +with pragmas though: warning 4244 about implicit conversions, and warning 4996 +where it wants to use a non-standard function fopen_s instead of the standard C +fopen. + +Visual Studio may want "stdafx.h" files to be included in each source file and +give an error "unexpected end of file while looking for precompiled header". +This is not standard C++ and will not be added to the stock LodePNG. You can +disable it for lodepng.cpp only by right clicking it, Properties, C/C++, +Precompiled Headers, and set it to Not Using Precompiled Headers there. + +NOTE: Modern versions of VS should be fully supported, but old versions, e.g. +VS6, are not guaranteed to work. + +*) Compilers on Macintosh + +LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for +C and C++. + +*) Other Compilers + +If you encounter problems on any compilers, feel free to let me know and I may +try to fix it if the compiler is modern and standards complient. + + +10. examples +------------ + +This decoder example shows the most basic usage of LodePNG. More complex +examples can be found on the LodePNG website. + +10.1. decoder C++ example +------------------------- + +#include "lodepng.h" +#include + +int main(int argc, char *argv[]) +{ + const char* filename = argc > 1 ? argv[1] : "test.png"; + + //load and decode + std::vector image; + unsigned width, height; + unsigned error = lodepng::decode(image, width, height, filename); + + //if there's an error, display it + if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; + + //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... +} + +10.2. decoder C example +----------------------- + +#include "lodepng.h" + +int main(int argc, char *argv[]) +{ + unsigned error; + unsigned char* image; + size_t width, height; + const char* filename = argc > 1 ? argv[1] : "test.png"; + + error = lodepng_decode32_file(&image, &width, &height, filename); + + if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); + + / * use image here * / + + free(image); + return 0; +} + + +11. changes +----------- + +The version number of LodePNG is the date of the change given in the format +yyyymmdd. + +Some changes aren't backwards compatible. Those are indicated with a (!) +symbol. + +*) 23 aug 2014: Reduced needless memory usage of decoder. +*) 28 jun 2014: Removed fix_png setting, always support palette OOB for + simplicity. Made ColorProfile public. +*) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization. +*) 22 dec 2013: Power of two windowsize required for optimization. +*) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. +*) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). +*) 11 mar 2013 (!): Bugfix with custom free. Changed from "my" to "lodepng_" + prefix for the custom allocators and made it possible with a new #define to + use custom ones in your project without needing to change lodepng's code. +*) 28 jan 2013: Bugfix with color key. +*) 27 okt 2012: Tweaks in text chunk keyword length error handling. +*) 8 okt 2012 (!): Added new filter strategy (entropy) and new auto color mode. + (no palette). Better deflate tree encoding. New compression tweak settings. + Faster color conversions while decoding. Some internal cleanups. +*) 23 sep 2012: Reduced warnings in Visual Studio a little bit. +*) 1 sep 2012 (!): Removed #define's for giving custom (de)compression functions + and made it work with function pointers instead. +*) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc + and free functions and toggle #defines from compiler flags. Small fixes. +*) 6 may 2012 (!): Made plugging in custom zlib/deflate functions more flexible. +*) 22 apr 2012 (!): Made interface more consistent, renaming a lot. Removed + redundant C++ codec classes. Reduced amount of structs. Everything changed, + but it is cleaner now imho and functionality remains the same. Also fixed + several bugs and shrinked the implementation code. Made new samples. +*) 6 nov 2011 (!): By default, the encoder now automatically chooses the best + PNG color model and bit depth, based on the amount and type of colors of the + raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. +*) 9 okt 2011: simpler hash chain implementation for the encoder. +*) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. +*) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. + A bug with the PNG filtertype heuristic was fixed, so that it chooses much + better ones (it's quite significant). A setting to do an experimental, slow, + brute force search for PNG filter types is added. +*) 17 aug 2011 (!): changed some C zlib related function names. +*) 16 aug 2011: made the code less wide (max 120 characters per line). +*) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. +*) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. +*) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman + to optimize long sequences of zeros. +*) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and + LodePNG_InfoColor_canHaveAlpha functions for convenience. +*) 7 nov 2010: added LodePNG_error_text function to get error code description. +*) 30 okt 2010: made decoding slightly faster +*) 26 okt 2010: (!) changed some C function and struct names (more consistent). + Reorganized the documentation and the declaration order in the header. +*) 08 aug 2010: only changed some comments and external samples. +*) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. +*) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. +*) 02 sep 2008: fixed bug where it could create empty tree that linux apps could + read by ignoring the problem but windows apps couldn't. +*) 06 jun 2008: added more error checks for out of memory cases. +*) 26 apr 2008: added a few more checks here and there to ensure more safety. +*) 06 mar 2008: crash with encoding of strings fixed +*) 02 feb 2008: support for international text chunks added (iTXt) +*) 23 jan 2008: small cleanups, and #defines to divide code in sections +*) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. +*) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. +*) 17 jan 2008: ability to encode and decode compressed zTXt chunks added + Also vareous fixes, such as in the deflate and the padding bits code. +*) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved + filtering code of encoder. +*) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A + C++ wrapper around this provides an interface almost identical to before. + Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code + are together in these files but it works both for C and C++ compilers. +*) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks +*) 30 aug 2007: bug fixed which makes this Borland C++ compatible +*) 09 aug 2007: some VS2005 warnings removed again +*) 21 jul 2007: deflate code placed in new namespace separate from zlib code +*) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images +*) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing + invalid std::vector element [0] fixed, and level 3 and 4 warnings removed +*) 02 jun 2007: made the encoder add a tag with version by default +*) 27 may 2007: zlib and png code separated (but still in the same file), + simple encoder/decoder functions added for more simple usage cases +*) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), + moved some examples from here to lodepng_examples.cpp +*) 12 may 2007: palette decoding bug fixed +*) 24 apr 2007: changed the license from BSD to the zlib license +*) 11 mar 2007: very simple addition: ability to encode bKGD chunks. +*) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding + palettized PNG images. Plus little interface change with palette and texts. +*) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. + Fixed a bug where the end code of a block had length 0 in the Huffman tree. +*) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented + and supported by the encoder, resulting in smaller PNGs at the output. +*) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. +*) 24 jan 2007: gave encoder an error interface. Added color conversion from any + greyscale type to 8-bit greyscale with or without alpha. +*) 21 jan 2007: (!) Totally changed the interface. It allows more color types + to convert to and is more uniform. See the manual for how it works now. +*) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: + encode/decode custom tEXt chunks, separate classes for zlib & deflate, and + at last made the decoder give errors for incorrect Adler32 or Crc. +*) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. +*) 29 dec 2006: Added support for encoding images without alpha channel, and + cleaned out code as well as making certain parts faster. +*) 28 dec 2006: Added "Settings" to the encoder. +*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. + Removed some code duplication in the decoder. Fixed little bug in an example. +*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. + Fixed a bug of the decoder with 16-bit per color. +*) 15 okt 2006: Changed documentation structure +*) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the + given image buffer, however for now it's not compressed. +*) 08 sep 2006: (!) Changed to interface with a Decoder class +*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different + way. Renamed decodePNG to decodePNGGeneric. +*) 29 jul 2006: (!) Changed the interface: image info is now returned as a + struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. +*) 28 jul 2006: Cleaned the code and added new error checks. + Corrected terminology "deflate" into "inflate". +*) 23 jun 2006: Added SDL example in the documentation in the header, this + example allows easy debugging by displaying the PNG and its transparency. +*) 22 jun 2006: (!) Changed way to obtain error value. Added + loadFile function for convenience. Made decodePNG32 faster. +*) 21 jun 2006: (!) Changed type of info vector to unsigned. + Changed position of palette in info vector. Fixed an important bug that + happened on PNGs with an uncompressed block. +*) 16 jun 2006: Internally changed unsigned into unsigned where + needed, and performed some optimizations. +*) 07 jun 2006: (!) Renamed functions to decodePNG and placed them + in LodePNG namespace. Changed the order of the parameters. Rewrote the + documentation in the header. Renamed files to lodepng.cpp and lodepng.h +*) 22 apr 2006: Optimized and improved some code +*) 07 sep 2005: (!) Changed to std::vector interface +*) 12 aug 2005: Initial release (C++, decoder only) + + +12. contact information +----------------------- + +Feel free to contact me with suggestions, problems, comments, ... concerning +LodePNG. If you encounter a PNG image that doesn't work properly with this +decoder, feel free to send it and I'll use it to find and fix the problem. + +My email address is (puzzle the account and domain together with an @ symbol): +Domain: gmail dot com. +Account: lode dot vandevenne. + + +Copyright (c) 2005-2014 Lode Vandevenne +*/ diff --git a/main.cc b/main.cc index 535705f..1d231fc 100644 --- a/main.cc +++ b/main.cc @@ -10,107 +10,61 @@ #include #include #include +#include +#include #include +#include -using namespace std; -using namespace ACGL::OpenGL; -using namespace ACGL::Base; -using namespace ACGL::Utils; - -glm::uvec2 g_windowSize( 1024, 786 ); -float g_nearPlane = 0.1f; -float g_farPlane = 100.0f; -bool glfwWindowClosed = false; - -GLFWwindow* g_window; - -void setGLFWHintsForOpenGLVersion( unsigned int _version ) -{ -#ifdef __APPLE__ -#if (ACGL_OPENGL_VERSION >= 30) - // request OpenGL 3.2, will return a 4.1 context on Mavericks - glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 ); - glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 2 ); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); -#endif -#else -// non-apple - glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, _version / 10 ); - glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, _version % 10 ); - #ifdef ACGL_OPENGL_PROFILE_CORE - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - #endif -#endif +Application::Application() { + graphics = Graphics(glm::uvec2(1024, 786), 0.1f, 100.0f); } -/********************************************************************************************************************** - * Returns true if a window with the desired context could get created. - * Requested OpenGL version gets set by ACGL defines. - */ -bool createWindow() +Graphics* Application::getGraphics() { + return &graphics; +} + +Level* Application::getLevel() { + return &level; +} + +ACGL::OpenGL::SharedShaderProgram Application::getShader() { + return shader; +} + +void Application::init() { - ///////////////////////////////////////////////////////////////////////////////////// - // Initialise GLFW - // - if ( !glfwInit() ) - { - error() << "Failed to initialize GLFW" << endl; - exit( -1 ); - } + // define where shaders and textures can be found: + ACGL::Base::Settings::the()->setResourcePath("../"); + ACGL::Base::Settings::the()->setShaderPath("Shader/"); + ACGL::Base::Settings::the()->setTexturePath("Levels/Textures/"); + ACGL::Base::Settings::the()->setGeometryPath("Levels/Geometry/"); - ///////////////////////////////////////////////////////////////////////////////////// - // Configure OpenGL context - // - setGLFWHintsForOpenGLVersion( ACGL_OPENGL_VERSION ); + // construct VAO to give shader correct Attribute locations + ACGL::OpenGL::SharedArrayBuffer ab = std::make_shared(); + ab->defineAttribute("aPosition", GL_FLOAT, 3); + ab->defineAttribute("aTexCoord", GL_FLOAT, 2); + ab->defineAttribute("aNormal", GL_FLOAT, 3); + ACGL::OpenGL::SharedVertexArrayObject vao = std::make_shared(); + vao->attachAllAttributes(ab); - // activate multisampling (second parameter is the number of samples): - //glfwWindowHint( GLFW_SAMPLES, 8 ); + // look up all shader files starting with 'phong' and build a ShaderProgram from it: + shader = ACGL::OpenGL::ShaderProgramCreator("phong").attributeLocations( + vao->getAttributeLocations()).create(); + shader->use(); - // request an OpenGL debug context: - glfwWindowHint( GLFW_OPENGL_DEBUG_CONTEXT, true ); + // load Level + level.load(shader); - // define whether the window can get resized: - //glfwWindowHint( GLFW_RESIZABLE, true ); + // just in case: check for errors + openGLCriticalError(); +} - // non-decorated windows can be used as splash screens: - //glfwWindowHint( GLFW_DECORATED, false ); - - // request an sRGB framebuffer: - //glfwWindowHint( GLFW_SRGB_CAPABLE, true ); - - //glfwWindowHint( , true ); - //glfwWindowHint( , true ); - //glfwWindowHint( , true ); - //glfwWindowHint( , true ); - - - ///////////////////////////////////////////////////////////////////////////////////// - // try to create an OpenGL context in a window and check the supported OpenGL version: - // R,G,B,A, Depth,Stencil - g_window = glfwCreateWindow( g_windowSize.x, g_windowSize.y, "ACGL GLFWExamples", NULL, NULL); - if (!g_window) { - error() << "Failed to open a GLFW window - requested OpenGL: " << ACGL_OPENGL_VERSION << endl; - return false; - } - glfwMakeContextCurrent(g_window); - ACGL::init(); - - ///////////////////////////////////////////////////////////////////////////////////// - // Init debug-extension - // - if (ACGL_ARB_debug_output()) { - //debug() << "GL_ARB_DEBUG_OUTPUT is supported, register callback" << endl; - //glDebugMessageCallbackARB( debugCallback, NULL); - - // filter out the strange performance warnings about shader recompiles: - //glDebugMessageControlARB( GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_PERFORMANCE_ARB, GL_DEBUG_SEVERITY_MEDIUM_ARB, 0, NULL, GL_FALSE ); - } else { - //debug() << "GL_ARB_DEBUG_OUTPUT is missing!" << endl; - } - return true; +void resizeCallback(GLFWwindow* window, int newWidth, int newHeight) +{ + // store the new window size and adjust the viewport: + app.getGraphics()->setWindowSize(glm::uvec2( newWidth, newHeight)); + glViewport( 0, 0, newWidth, newHeight); } static void keyCallback(GLFWwindow* _window, int _key, int, int _action, int) @@ -120,16 +74,19 @@ static void keyCallback(GLFWwindow* _window, int _key, int, int _action, int) } } +static void scrollCallback(GLFWwindow* window, double xoffset, double yoffset) { + app.getLevel()->getCamera()->updateDistance(-(float)yoffset); +} + -/********************************************************************************************************************** - * Generic main for different example apps - */ int main( int argc, char *argv[] ) { + //Application app = Application(); + ///////////////////////////////////////////////////////////////////////////////////// // Create OpenGL capable window: // - if ( !createWindow() ) { + if ( !app.getGraphics()->createWindow() ) { glfwTerminate(); exit( -1 ); } @@ -137,12 +94,15 @@ int main( int argc, char *argv[] ) ///////////////////////////////////////////////////////////////////////////////////// // Set window title to binary name (without the path): // - std::vector tmp = StringHelpers::split( std::string( argv[0] ), '/' ); - glfwSetWindowTitle( g_window, tmp[tmp.size()-1].c_str() ); + std::vector tmp = ACGL::Utils::StringHelpers::split( std::string( argv[0] ), '/' ); + glfwSetWindowTitle(app.getGraphics()->getWindow(), tmp[tmp.size()-1].c_str() ); // Ensure we can capture the escape key being pressed below - glfwSetInputMode( g_window, GLFW_STICKY_KEYS, 1 ); - glfwSetWindowSizeCallback( g_window, resizeCallback ); - glfwSetKeyCallback( g_window, keyCallback ); + glfwSetInputMode(app.getGraphics()->getWindow(), GLFW_STICKY_KEYS, 1); + // Hide mouse cursor + glfwSetInputMode(app.getGraphics()->getWindow(), GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + glfwSetWindowSizeCallback(app.getGraphics()->getWindow(), resizeCallback); + glfwSetKeyCallback(app.getGraphics()->getWindow(), keyCallback ); + glfwSetScrollCallback(app.getGraphics()->getWindow(), scrollCallback ); // Enable vertical sync (on cards that support it) with parameter 1 - 0 means off glfwSwapInterval( 0 ); @@ -152,38 +112,54 @@ int main( int argc, char *argv[] ) // glClearColor( 0.0, 0.0, 0.0, 1.0 ); glEnable( GL_DEPTH_TEST ); - initCustomResources(); + app.init(); int frameCount = 0; const double FPSdelay = 2.0; double startTimeInSeconds = glfwGetTime(); double showNextFPS = startTimeInSeconds + FPSdelay; + + double lastUpdate=0.0f; + + int stateW = glfwGetKey(app.getGraphics()->getWindow(), GLFW_KEY_W); + int stateA = glfwGetKey(app.getGraphics()->getWindow(), GLFW_KEY_A); + int stateS = glfwGetKey(app.getGraphics()->getWindow(), GLFW_KEY_S); + int stateD = glfwGetKey(app.getGraphics()->getWindow(), GLFW_KEY_D); do { - double now = glfwGetTime(); + double now = glfwGetTime()- startTimeInSeconds; + if (showNextFPS <= now) { - stringstream sstream (stringstream::in | stringstream::out); - sstream << setprecision(1) << std::fixed + std::stringstream sstream (std::stringstream::in | std::stringstream::out); + sstream << std::setprecision(1) << std::fixed << tmp[tmp.size()-1] << " - FPS: " << frameCount / (now-showNextFPS + FPSdelay) << " " << 1000 * (now-showNextFPS + FPSdelay)/frameCount << " msec"; - glfwSetWindowTitle( g_window, sstream.str().c_str() ); + glfwSetWindowTitle(app.getGraphics()->getWindow(), sstream.str().c_str() ); showNextFPS = now + FPSdelay; frameCount = 0; } - draw( now - startTimeInSeconds ); + double xpos, ypos; + glfwGetCursorPos(app.getGraphics()->getWindow(), &xpos, &ypos); + glfwSetCursorPos(app.getGraphics()->getWindow(), app.getGraphics()->getWindowSize().x/2, app.getGraphics()->getWindowSize().y/2); + + app.getLevel()->update(now - lastUpdate, + glm::vec2((float)ypos-app.getGraphics()->getWindowSize().y/2, + (float)xpos-app.getGraphics()->getWindowSize().x/2), + stateW == GLFW_PRESS,stateA == GLFW_PRESS,stateS == GLFW_PRESS,stateD == GLFW_PRESS); + lastUpdate = now; + app.getGraphics()->render(app.getLevel(), app.getShader()); + openGLCriticalError(); // MacOS X will not swap correctly is another FBO is bound: glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - glfwSwapBuffers( g_window ); + glfwSwapBuffers(app.getGraphics()->getWindow()); glfwPollEvents(); frameCount++; } // Check if the window was closed - while( !glfwWindowShouldClose( g_window ) ); - - deleteCustomResources(); + while( !glfwWindowShouldClose(app.getGraphics()->getWindow()) ); glfwTerminate(); exit(0); diff --git a/main.hh b/main.hh index dfc33d3..469dd4b 100644 --- a/main.hh +++ b/main.hh @@ -1,27 +1,29 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// headers needed: -// -#include +#ifndef MAIN_HH_INCLUDED +#define MAIN_HH_INCLUDED #include +#include #include #include -// -/////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// #include "physics.hh" #include "graphics.hh" #include "level.hh" -/////////////////////////////////////////////////////////////////////////////////////////////////// -// -// implement the following functions: -// +///////////////////////////////////////////////////////////////// +class Application { + public: + Application(); + Graphics* getGraphics(); + Level* getLevel(); + ACGL::OpenGL::SharedShaderProgram getShader(); + void init(); + private: + Graphics graphics; + Level level; + ACGL::OpenGL::SharedShaderProgram shader; +}; -// global variables exported by the generic main: -extern glm::uvec2 g_windowSize; -extern float g_nearPlane; -extern float g_farPlane; -// -/////////////////////////////////////////////////////////////////////////////////////////////////// +Application app; +#endif diff --git a/model.cc b/model.cc index 1800572..22e0e7c 100644 --- a/model.cc +++ b/model.cc @@ -2,14 +2,12 @@ Model::Model(std::string filePath, float scale) { reference = ACGL::OpenGL::VertexArrayObjectCreator(filePath).create(); - reference->bind(); this->scale = scale; } -Model::Model(std::string filePath) { - reference = ACGL::OpenGL::VertexArrayObjectCreator(filePath).create(); - reference->bind(); - this->scale = 1.0f; +Model::Model(ACGL::OpenGL::SharedVertexArrayObject vao, float scale){ + reference = vao; + this->scale = scale; } Model::Model(){ diff --git a/model.hh b/model.hh index 70391d6..e73c4e9 100644 --- a/model.hh +++ b/model.hh @@ -6,8 +6,8 @@ class Model { public: - Model(std::string filePath, float scale); - Model(std::string filePath); + Model(std::string filePath, float scale=1.0f); + Model(ACGL::OpenGL::SharedVertexArrayObject vao, float scale=1.0f); Model(); ~Model(); ACGL::OpenGL::SharedVertexArrayObject getReference(); diff --git a/object.cc b/object.cc index a917b4f..7bd7580 100644 --- a/object.cc +++ b/object.cc @@ -24,9 +24,7 @@ void Object::render() { shader->setUniform("shininess", material.getShininess()); shader->setTexture("uTexture", material.getReference(), 0); // set model matrix - glm::mat4 rotationMatrix = glm::rotate(this->getRotation()[0], glm::vec3(1.0f, 0.0f, 0.0f)) * - glm::rotate(this->getRotation()[1], glm::vec3(0.0f, 1.0f, 0.0f)) * glm::rotate(this->getRotation()[2], glm::vec3(0.0f, 0.0f, 1.0f)); - glm::mat4 modelMatrix = glm::translate(this->getPosition()) * rotationMatrix * glm::scale(glm::vec3(model.getScale())); + glm::mat4 modelMatrix = glm::translate(getPosition()) * getRotation() * glm::scale(glm::vec3(model.getScale())); shader->setUniform( "modelMatrix", modelMatrix); // draw model.getReference()->render(); diff --git a/physics.cc b/physics.cc index cf030ff..d16d490 100644 --- a/physics.cc +++ b/physics.cc @@ -1,7 +1,5 @@ #include "physics.hh" -#include - btDynamicsWorld* world; //contains physical attributes of the world. btDispatcher* dispatcher; // @@ -12,8 +10,16 @@ btConstraintSolver* solver; //solver for forces and impulses. std::vector bodies; //list of all bodies. bodies are also in world, but save again to ease cleaning up process. btRigidBody* playerBall; btRigidBody* terrainBody; +btRigidBody* staticGroundBody; -void init() + +Physics::Physics() { +} + +Physics::~Physics() { +} + +void Physics::init() { colConfig = new btDefaultCollisionConfiguration(); dispatcher = new btCollisionDispatcher(colConfig); @@ -21,17 +27,15 @@ void init() solver = new btSequentialImpulseConstraintSolver(); world = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,colConfig); - world->setGravity(btVector3(0,-10,-0)); - - + world->setGravity(btVector3(0,-10,-0)); } -void takeUpdateStep(float timeDiff) +void Physics::takeUpdateStep(float timeDiff) { world->stepSimulation(timeDiff); } -void addTerrain(int width, int length, float** heightData) +void Physics::addTerrain(int width, int length, float** heightData) { float* heightfield = new float[width * length]; int highest = -999999, j = 0, i = 0; @@ -70,14 +74,52 @@ void addTerrain(int width, int length, float** heightData) } -void addSphere(float rad, float x, float y, float z, float mass, int indice) //TODO add indice check +void Physics::addStaticGroundPlane() { + btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0, 1, 0), 0); + btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 0, 0))); + btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(0, groundMotionState, groundShape, btVector3(0, 0, 0)); + staticGroundBody = new btRigidBody(groundRigidBodyCI); + + world->addRigidBody(staticGroundBody); +} + +void Physics::addPlayer(float rad, float x, float y, float z, float mass, unsigned indice) +{ + if(bodies.size() != indice) + throw std::invalid_argument( "Bodies out of Sync" ); + btSphereShape* sphere = new btSphereShape(rad); btVector3 inertia(0,0,0); - if(mass == 0.0) + if(mass != 0.0) { + sphere->calculateLocalInertia((btScalar)mass,inertia); } - else + + btDefaultMotionState* motion = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(x,y,z))); + + btRigidBody::btRigidBodyConstructionInfo info(mass,motion,sphere,inertia); + + playerBall = new btRigidBody(info); + + world->addRigidBody(playerBall); + + bodies.push_back(playerBall); + + if(bodies.size() == indice) + throw std::invalid_argument( "Bodies out of Sync" ); + +} + + +void Physics::addSphere(float rad, float x, float y, float z, float mass, unsigned indice) +{ + if(bodies.size() != indice) + throw std::invalid_argument( "Bodies out of Sync" ); + + btSphereShape* sphere = new btSphereShape(rad); + btVector3 inertia(0,0,0); + if(mass != 0.0) { sphere->calculateLocalInertia((btScalar)mass,inertia); } @@ -91,23 +133,41 @@ void addSphere(float rad, float x, float y, float z, float mass, int indice) //T world->addRigidBody(body); bodies.push_back(body); + + + if(bodies.size() == indice) + throw std::invalid_argument( "Bodies out of Sync" ); + } -glm::vec3 getPos(int i) +glm::vec3 Physics::getPos(int i) { btVector3 origin = bodies[i]->getCenterOfMassPosition(); glm::vec3 save(origin.getX(),origin.getY(),origin.getZ()); return save; } -void getRotation(int i) +glm::mat4 Physics::getRotation(int i) { - btQuaternion rotQuantrino = bodies[i]->getOrientation(); //TODO return orientation in gl format + btQuaternion quat = bodies[i]->getOrientation(); + + glm::mat4 matrix = glm::rotate( + quat.getAngle(), + glm::vec3(quat.getAxis().getX(), quat.getAxis().getY(), quat.getAxis().getZ()) + ); + return matrix; } -void rollForward() +void Physics::rollForward(glm::vec3 camPos) { - //bodies[k].applyTorque(btVector3); + btVector3 pos(camPos.x,camPos.y,camPos.z); + pos -= playerBody->getCenterOfMassPosition(); + pos.cross(btVector3(0,1,0)); + playerBall->applyTorque(pos); + +/* glm::vec3 saveVector= glm::vec3(1,0,0) * rotCamera; + saveVector = glm::cross(glm::vec3(0,1,0),saveVector); + playerBall->applyTorque(btVector3(saveVector[0],saveVector[1],saveVector[2]));*/ } /* diff --git a/physics.hh b/physics.hh index a52e646..c2d7774 100644 --- a/physics.hh +++ b/physics.hh @@ -11,6 +11,7 @@ #include "extern/bullet/src/BulletCollision/CollisionShapes/btSphereShape.h" #include "extern/bullet/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h" +#include "extern/bullet/src/BulletCollision/CollisionShapes/btStaticPlaneShape.h" #include "extern/bullet/src/BulletDynamics/ConstraintSolver/btConstraintSolver.h" #include "extern/bullet/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h"//YAY! @@ -26,24 +27,29 @@ #include "extern/bullet/src/LinearMath/btMotionState.h" #include "extern/bullet/src/LinearMath/btDefaultMotionState.h" #include "extern/bullet/src/LinearMath/btQuaternion.h" +#include "extern/bullet/src/LinearMath/btVector3.h" +#include "extern/bullet/src/LinearMath/btMatrix3x3.h" class Physics { public: - Physics(); + Physics(); ~Physics(); void init(); void takeUpdateStep(float timeDiff); void rollForward(glm::vec3 camPos, float strength); glm::vec3 getPos(int i); - void getRotation(int i); - void rollForward(); + glm::mat4 getRotation(int i); + void rollForward(glm::vec3 camPos); + void addStaticGroundPlane(); void addTerrain(int width, int length, float** heightData); - void addSphere(float rad, float x, float y, float z, float mass, int indice); + void addPlayer(float rad, float x, float y, float z, float mass, unsigned indice); + void addSphere(float rad, float x, float y, float z, float mass, unsigned indice); private: btRigidBody* playerBody; btRigidBody* terrainBody; std::vector bodies; //list of all bodies. bodies are also in world, but save again to ease cleaning up process. + btRigidBody* staticGroundBody; btDynamicsWorld* world; //contains physical attributes of the world. diff --git a/terrain.cc b/terrain.cc index 6db6db5..e27e4b5 100644 --- a/terrain.cc +++ b/terrain.cc @@ -1,4 +1,5 @@ #include "terrain.hh" +#include "lodepng.h" Terrain::Terrain(std::string filePath){ this->filePath = filePath; @@ -12,28 +13,21 @@ Terrain::~Terrain() { void Terrain::load() { - this->filePath = "../Levels/LevelTest/terrain"; //TODO remove this, its only for testing + filePath = "../Levels/heightmapLvlTest.png"; //TODO remove this, its only for testing - std::ifstream terrain_png(this->filePath + "/heightmap.png"); - unsigned int rowNum, columnNum, heightmapValue; - - terrain_png.seekg(16); //skip part of the header - - char temp[4]; - terrain_png.read(temp, 4); //read width - this->heightmapWidth = (temp[3]<<0) | (temp[2]<<8) | (temp[1]<<16) | (temp[0]<<24); //convert from network to host byte order - terrain_png.read(temp, 4); //read height - this->heightmapHeight = (temp[3]<<0) | (temp[2]<<8) | (temp[1]<<16) | (temp[0]<<24); //convert from network to host byte order - - heightmap = new float*[this->heightmapHeight]; //initialize the heightmap - for(rowNum = 0; rowNum < this->heightmapHeight; rowNum++){ //read in the heightmap - heightmap[rowNum] = new float[this->heightmapWidth]; - for(columnNum = 0; columnNum < this->heightmapWidth; columnNum++){ - terrain_png.read((char *)&heightmapValue, 1); - heightmap[rowNum][columnNum] = (float)heightmapValue / 256; + std::vector image; //the raw pixels + unsigned error = lodepng::decode(image, heightmapWidth, heightmapHeight, filePath); + if (error) { + std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; + } + this->heightmap = new float*[this->heightmapHeight]; //initialize the heightmap + for(unsigned int rowNum = 0; rowNum < this->heightmapHeight; rowNum++){ //read in the heightmap + this->heightmap[rowNum] = new float[this->heightmapWidth]; + for(unsigned int columnNum = 0; columnNum < this->heightmapWidth; columnNum++){ + this->heightmap[rowNum][columnNum] = (float)(image[(rowNum*heightmapWidth+columnNum)*4]) / 32; } } - + this->makeTriangleMesh(); heightmapChanged = false; //no need to make a TriangleMesh again before rendering @@ -42,56 +36,53 @@ void Terrain::load() { void Terrain::makeTriangleMesh(){ ACGL::OpenGL::SharedArrayBuffer ab = std::make_shared(); - ab->defineAttribute("pos", GL_FLOAT, 3); //TODO: ArrayBuffer for the texture coordinates + // Do NOT change the order of this! + ab->defineAttribute("aPosition", GL_FLOAT, 3); + ab->defineAttribute("aTexCoord", GL_FLOAT, 2); + ab->defineAttribute("aNormal", GL_FLOAT, 3); - unsigned int rowNum=0, columnNum=0, dataCount=0; //initializing: + unsigned int rowNum=0, columnNum=0, dataCount=0, floatsPerVertex=8; //initializing: bool movingRight = true, isUp = true; int numVertices = (this->heightmapHeight - 1) * (this->heightmapWidth * 2 + 1) + 1; - float* abData = new float[numVertices * 3]; + float* abData = new float[numVertices * floatsPerVertex]; - while(rowNum < this->heightmapHeight){ //traversing the Triangle Strip! - abData[dataCount] = (float)rowNum; - abData[dataCount+1] = heightmap[rowNum][columnNum]; - abData[dataCount+2] = (float)columnNum; - dataCount += 3; + while(rowNum < this->heightmapHeight){ //traversing the Triangle Strip! + set_abData(abData, dataCount, rowNum, columnNum); + dataCount += floatsPerVertex; if (isUp){ rowNum = rowNum + 1; isUp = false; - }else if (movingRight){ - if (columnNum == this->heightmapWidth - 1){ - abData[dataCount] = (float)rowNum; - abData[dataCount+1] = heightmap[rowNum][columnNum]; - abData[dataCount+2] = (float)columnNum; - dataCount += 3; - abData[dataCount] = (float)rowNum; - abData[dataCount+1] = heightmap[rowNum][columnNum]; - abData[dataCount+2] = (float)columnNum; - dataCount += 3; - movingRight = false; - rowNum = rowNum + 1; - } else{ - rowNum = rowNum - 1; - columnNum = columnNum + 1; - isUp = true; - } - }else{ - if (columnNum == 0){ - abData[dataCount] = (float)rowNum; - abData[dataCount+1] = heightmap[rowNum][columnNum]; - abData[dataCount+2] = (float)columnNum; - dataCount += 3; - abData[dataCount] = (float)rowNum; - abData[dataCount+1] = heightmap[rowNum][columnNum]; - abData[dataCount+2] = (float)columnNum; - dataCount += 3; - movingRight = true; - rowNum = rowNum + 1; - }else{ - rowNum = rowNum - 1; - columnNum = columnNum - 1; - isUp = true; - } } + else if (movingRight) { + if (columnNum == this->heightmapWidth - 1) { + set_abData(abData, dataCount, rowNum, columnNum); + dataCount += floatsPerVertex; + set_abData(abData, dataCount, rowNum, columnNum); + dataCount += floatsPerVertex; + movingRight = false; + rowNum = rowNum + 1; + } + else { + rowNum = rowNum - 1; + columnNum = columnNum + 1; + isUp = true; + } + } + else { + if (columnNum == 0){ + set_abData(abData, dataCount, rowNum, columnNum); + dataCount += floatsPerVertex; + set_abData(abData, dataCount, rowNum, columnNum); + dataCount += floatsPerVertex; + movingRight = true; + rowNum = rowNum + 1; + } + else { + rowNum = rowNum - 1; + columnNum = columnNum - 1; + isUp = true; + } + } } ab->setDataElements(numVertices, abData); @@ -99,39 +90,58 @@ void Terrain::makeTriangleMesh(){ this->triangleMesh->bind(); this->triangleMesh->setMode(GL_TRIANGLE_STRIP); this->triangleMesh->attachAllAttributes(ab); - //TODO unbind? +} - //TODO remove this TestCode (that doesnt even work yet...): -/* ACGL::OpenGL::SharedArrayBuffer tex = std::make_shared(); - tex->defineAttribute("color", GL_FLOAT, 3); - float* texData = new float[numVertices*3]; - for (int i=0; iheightmapHeight-1) || columnNum==0 || columnNum==(this->heightmapWidth-1)){ + abData[dataCount+5] = 0.0; + abData[dataCount+6] = 1.0; + abData[dataCount+7] = 0.0; + } + else { + glm::vec3 sumNormals = glm::vec3(0.0f, 0.0f, 0.0f); + for (int i=-1; i<2; i+=2) { + for (int j=-1; j<2; j+=2) { + glm::vec3 vecA, vecB, normal; + vecA = glm::vec3((float)i, (heightmap[rowNum+i][columnNum] - heightmap[rowNum][columnNum]), 0.0f); + vecB = glm::vec3(0.0f, (heightmap[rowNum][columnNum+j] - heightmap[rowNum][columnNum]), (float)j); + normal = glm::normalize(glm::cross(vecA, vecB)); + if(i+j!=0) + normal = normal*(-1.0f); + sumNormals += normal; + } + } + sumNormals = glm::normalize(sumNormals); + abData[dataCount+5] = sumNormals[0]; + abData[dataCount+6] = sumNormals[1]; + abData[dataCount+7] = sumNormals[2]; } - tex->setDataElements(numVertices, texData); - this->triangleMesh->attachAllAttributes(tex); -*/ - - } -void Terrain::render() { - if (heightmapChanged) - this->makeTriangleMesh(); - this->triangleMesh->render(); +Model Terrain::getModel(){ + return Model(this->triangleMesh); } +float** Terrain::getHeightmap(){ + return this->heightmap; +} +unsigned int Terrain::getHeightmapHeight(){ + return this->heightmapHeight; +} - - - - - - - - - - +unsigned int Terrain::getHeightmapWidth(){ + return this->heightmapWidth; +} diff --git a/terrain.hh b/terrain.hh index 8418e8b..263ea30 100644 --- a/terrain.hh +++ b/terrain.hh @@ -3,9 +3,8 @@ #include #include "material.hh" -#include #include - +#include "model.hh" class Terrain { public: Terrain(std::string filePath); @@ -13,15 +12,21 @@ class Terrain { ~Terrain(); void load(); void render(); + Model getModel(); + float** getHeightmap(); + unsigned int getHeightmapHeight(); + unsigned int getHeightmapWidth(); + private: Material material; std::string filePath; - unsigned int heightmapWidth, heightmapHeight; + unsigned int heightmapHeight, heightmapWidth; float** heightmap; //can be accessed like 'float[][]' bool heightmapChanged; ACGL::OpenGL::SharedVertexArrayObject triangleMesh; void makeTriangleMesh(); + void set_abData(float* abData, unsigned int dataCount, unsigned int rowNum, unsigned int columnNum); }; #endif