From 4343b942dc63c064cc9928d14122aa586c6389e5 Mon Sep 17 00:00:00 2001 From: Relintai Date: Fri, 22 Apr 2022 20:23:33 +0200 Subject: [PATCH] Initial commit. --- .gitignore | 32 + HEADS | 1 + LICENSE | 22 + Makefile | 20 + README.md | 49 + SConstruct | 652 ++ build.config.example | 45 + editor.bat | 6 + editor.sh | 6 + ged.sh | 6 + lged.sh | 6 + module_config.py | 18 + original_examples/.vscode/settings.json | 5 + original_examples/CMakeLists.txt | 23 + original_examples/samples.xml | 77 + original_examples/samples/3Bricks.png | Bin 0 -> 351 bytes original_examples/samples/Angular.png | Bin 0 -> 179 bytes original_examples/samples/Castle/bridge.png | Bin 0 -> 129 bytes original_examples/samples/Castle/data.xml | 74 + original_examples/samples/Castle/ground.png | Bin 0 -> 98 bytes original_examples/samples/Castle/river.png | Bin 0 -> 105 bytes .../samples/Castle/riverturn.png | Bin 0 -> 125 bytes original_examples/samples/Castle/road.png | Bin 0 -> 114 bytes original_examples/samples/Castle/roadturn.png | Bin 0 -> 129 bytes original_examples/samples/Castle/t.png | Bin 0 -> 124 bytes original_examples/samples/Castle/tower.png | Bin 0 -> 117 bytes original_examples/samples/Castle/wall.png | Bin 0 -> 131 bytes .../samples/Castle/wallriver.png | Bin 0 -> 148 bytes original_examples/samples/Castle/wallroad.png | Bin 0 -> 149 bytes original_examples/samples/Cat.png | Bin 0 -> 262 bytes original_examples/samples/Cats.png | Bin 0 -> 260 bytes original_examples/samples/Cave.png | Bin 0 -> 168 bytes original_examples/samples/Chess.png | Bin 0 -> 106 bytes original_examples/samples/Circles/b.png | Bin 0 -> 103 bytes original_examples/samples/Circles/b_half.png | Bin 0 -> 474 bytes original_examples/samples/Circles/b_i.png | Bin 0 -> 559 bytes .../samples/Circles/b_quarter.png | Bin 0 -> 509 bytes original_examples/samples/Circles/data.xml | 118 + original_examples/samples/Circles/w.png | Bin 0 -> 119 bytes original_examples/samples/Circles/w_half.png | Bin 0 -> 464 bytes original_examples/samples/Circles/w_i.png | Bin 0 -> 566 bytes .../samples/Circles/w_quarter.png | Bin 0 -> 554 bytes original_examples/samples/Circuit/bridge.png | Bin 0 -> 134 bytes .../samples/Circuit/component.png | Bin 0 -> 103 bytes .../samples/Circuit/connection.png | Bin 0 -> 168 bytes original_examples/samples/Circuit/corner.png | Bin 0 -> 116 bytes original_examples/samples/Circuit/data.xml | 182 + original_examples/samples/Circuit/dskew.png | Bin 0 -> 190 bytes original_examples/samples/Circuit/skew.png | Bin 0 -> 180 bytes .../samples/Circuit/substrate.png | Bin 0 -> 103 bytes original_examples/samples/Circuit/t.png | Bin 0 -> 133 bytes original_examples/samples/Circuit/track.png | Bin 0 -> 118 bytes .../samples/Circuit/transition.png | Bin 0 -> 185 bytes original_examples/samples/Circuit/turn.png | Bin 0 -> 148 bytes original_examples/samples/Circuit/viad.png | Bin 0 -> 159 bytes original_examples/samples/Circuit/vias.png | Bin 0 -> 185 bytes original_examples/samples/Circuit/wire.png | Bin 0 -> 116 bytes original_examples/samples/City.png | Bin 0 -> 160 bytes original_examples/samples/Colored City.png | Bin 0 -> 211 bytes original_examples/samples/Dungeon.png | Bin 0 -> 205 bytes original_examples/samples/Fabric.png | Bin 0 -> 120 bytes original_examples/samples/Flowers.png | Bin 0 -> 271 bytes original_examples/samples/Forest.png | Bin 0 -> 169 bytes original_examples/samples/Hogs.png | Bin 0 -> 186 bytes original_examples/samples/Knot.png | Bin 0 -> 177 bytes original_examples/samples/Knots/corner.png | Bin 0 -> 155 bytes original_examples/samples/Knots/cross.png | Bin 0 -> 181 bytes original_examples/samples/Knots/data.xml | 89 + original_examples/samples/Knots/empty.png | Bin 0 -> 99 bytes original_examples/samples/Knots/line.png | Bin 0 -> 117 bytes original_examples/samples/Knots/t.png | Bin 0 -> 146 bytes original_examples/samples/Lake.png | Bin 0 -> 326 bytes original_examples/samples/Less Rooms.png | Bin 0 -> 172 bytes original_examples/samples/Link 2.png | Bin 0 -> 198 bytes original_examples/samples/Link.png | Bin 0 -> 213 bytes original_examples/samples/Magic Office.png | Bin 0 -> 216 bytes original_examples/samples/Maze.png | Bin 0 -> 200 bytes original_examples/samples/Mazelike.png | Bin 0 -> 250 bytes original_examples/samples/More Flowers.png | Bin 0 -> 318 bytes original_examples/samples/Mountains.png | Bin 0 -> 160 bytes original_examples/samples/Nested.png | Bin 0 -> 195 bytes original_examples/samples/Office 2.png | Bin 0 -> 332 bytes original_examples/samples/Office.png | Bin 0 -> 171 bytes original_examples/samples/Paths.png | Bin 0 -> 173 bytes original_examples/samples/Platformer.png | Bin 0 -> 451 bytes original_examples/samples/Qud.png | Bin 0 -> 203 bytes original_examples/samples/Red Dot.png | Bin 0 -> 167 bytes original_examples/samples/Red Maze.png | Bin 0 -> 105 bytes original_examples/samples/Rooms.png | Bin 0 -> 181 bytes original_examples/samples/Rooms/bend.png | Bin 0 -> 102 bytes original_examples/samples/Rooms/corner.png | Bin 0 -> 99 bytes original_examples/samples/Rooms/corridor.png | Bin 0 -> 101 bytes original_examples/samples/Rooms/data.xml | 55 + original_examples/samples/Rooms/door.png | Bin 0 -> 97 bytes original_examples/samples/Rooms/empty.png | Bin 0 -> 101 bytes original_examples/samples/Rooms/side.png | Bin 0 -> 95 bytes original_examples/samples/Rooms/t.png | Bin 0 -> 98 bytes original_examples/samples/Rooms/turn.png | Bin 0 -> 100 bytes original_examples/samples/Rooms/wall.png | Bin 0 -> 89 bytes original_examples/samples/Rule 126.png | Bin 0 -> 516 bytes original_examples/samples/Scaled Maze.png | Bin 0 -> 135 bytes original_examples/samples/Sewers.png | Bin 0 -> 287 bytes original_examples/samples/Simple Knot.png | Bin 0 -> 148 bytes original_examples/samples/Simple Maze.png | Bin 0 -> 99 bytes original_examples/samples/Simple Wall.png | Bin 0 -> 138 bytes original_examples/samples/Skew 1.png | Bin 0 -> 253 bytes original_examples/samples/Skew 2.png | Bin 0 -> 259 bytes original_examples/samples/Skyline 2.png | Bin 0 -> 6424 bytes original_examples/samples/Skyline.png | Bin 0 -> 330 bytes original_examples/samples/Smile City.png | Bin 0 -> 163 bytes original_examples/samples/Spirals.png | Bin 0 -> 207 bytes original_examples/samples/Summer/cliff 0.png | Bin 0 -> 4906 bytes original_examples/samples/Summer/cliff 1.png | Bin 0 -> 5113 bytes original_examples/samples/Summer/cliff 2.png | Bin 0 -> 4806 bytes original_examples/samples/Summer/cliff 3.png | Bin 0 -> 5475 bytes .../samples/Summer/cliffcorner 0.png | Bin 0 -> 4621 bytes .../samples/Summer/cliffcorner 1.png | Bin 0 -> 4608 bytes .../samples/Summer/cliffcorner 2.png | Bin 0 -> 4865 bytes .../samples/Summer/cliffcorner 3.png | Bin 0 -> 4975 bytes .../samples/Summer/cliffturn 0.png | Bin 0 -> 5251 bytes .../samples/Summer/cliffturn 1.png | Bin 0 -> 5167 bytes .../samples/Summer/cliffturn 2.png | Bin 0 -> 5266 bytes .../samples/Summer/cliffturn 3.png | Bin 0 -> 5198 bytes original_examples/samples/Summer/data.xml | 68 + original_examples/samples/Summer/grass 0.png | Bin 0 -> 4094 bytes .../samples/Summer/grasscorner 0.png | Bin 0 -> 5891 bytes .../samples/Summer/grasscorner 1.png | Bin 0 -> 5942 bytes .../samples/Summer/grasscorner 2.png | Bin 0 -> 5932 bytes .../samples/Summer/grasscorner 3.png | Bin 0 -> 5923 bytes original_examples/samples/Summer/road 0.png | Bin 0 -> 5853 bytes original_examples/samples/Summer/road 1.png | Bin 0 -> 5848 bytes original_examples/samples/Summer/road 2.png | Bin 0 -> 5870 bytes original_examples/samples/Summer/road 3.png | Bin 0 -> 5834 bytes .../samples/Summer/roadturn 0.png | Bin 0 -> 5763 bytes .../samples/Summer/roadturn 1.png | Bin 0 -> 5681 bytes .../samples/Summer/roadturn 2.png | Bin 0 -> 5654 bytes .../samples/Summer/roadturn 3.png | Bin 0 -> 5645 bytes .../samples/Summer/water_a 0.png | Bin 0 -> 3962 bytes .../samples/Summer/water_b 0.png | Bin 0 -> 4339 bytes .../samples/Summer/water_c 0.png | Bin 0 -> 4337 bytes .../samples/Summer/watercorner 0.png | Bin 0 -> 4635 bytes .../samples/Summer/watercorner 1.png | Bin 0 -> 4688 bytes .../samples/Summer/watercorner 2.png | Bin 0 -> 4918 bytes .../samples/Summer/watercorner 3.png | Bin 0 -> 5016 bytes .../samples/Summer/waterside 0.png | Bin 0 -> 4700 bytes .../samples/Summer/waterside 1.png | Bin 0 -> 5370 bytes .../samples/Summer/waterside 2.png | Bin 0 -> 4705 bytes .../samples/Summer/waterside 3.png | Bin 0 -> 4802 bytes .../samples/Summer/waterturn 0.png | Bin 0 -> 5212 bytes .../samples/Summer/waterturn 1.png | Bin 0 -> 5173 bytes .../samples/Summer/waterturn 2.png | Bin 0 -> 5133 bytes .../samples/Summer/waterturn 3.png | Bin 0 -> 5011 bytes original_examples/samples/Town.png | Bin 0 -> 214 bytes original_examples/samples/Trick Knot.png | Bin 0 -> 193 bytes original_examples/samples/Village.png | Bin 0 -> 173 bytes original_examples/samples/Water.png | Bin 0 -> 149 bytes original_examples/src/include/color.hpp | 32 + .../src/include/external/rapidxml.hpp | 2969 +++++++ .../src/include/external/stb_image.h | 7462 +++++++++++++++++ .../src/include/external/stb_image_write.h | 1568 ++++ original_examples/src/include/image.hpp | 43 + .../src/include/rapidxml_utils.hpp | 32 + original_examples/src/include/utils.hpp | 23 + original_examples/src/lib/main.cpp | 342 + 164 files changed, 14025 insertions(+) create mode 100644 .gitignore create mode 100644 HEADS create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 SConstruct create mode 100644 build.config.example create mode 100644 editor.bat create mode 100755 editor.sh create mode 100755 ged.sh create mode 100755 lged.sh create mode 100644 module_config.py create mode 100644 original_examples/.vscode/settings.json create mode 100644 original_examples/CMakeLists.txt create mode 100644 original_examples/samples.xml create mode 100644 original_examples/samples/3Bricks.png create mode 100644 original_examples/samples/Angular.png create mode 100644 original_examples/samples/Castle/bridge.png create mode 100644 original_examples/samples/Castle/data.xml create mode 100644 original_examples/samples/Castle/ground.png create mode 100644 original_examples/samples/Castle/river.png create mode 100644 original_examples/samples/Castle/riverturn.png create mode 100644 original_examples/samples/Castle/road.png create mode 100644 original_examples/samples/Castle/roadturn.png create mode 100644 original_examples/samples/Castle/t.png create mode 100644 original_examples/samples/Castle/tower.png create mode 100644 original_examples/samples/Castle/wall.png create mode 100644 original_examples/samples/Castle/wallriver.png create mode 100644 original_examples/samples/Castle/wallroad.png create mode 100644 original_examples/samples/Cat.png create mode 100644 original_examples/samples/Cats.png create mode 100644 original_examples/samples/Cave.png create mode 100644 original_examples/samples/Chess.png create mode 100644 original_examples/samples/Circles/b.png create mode 100644 original_examples/samples/Circles/b_half.png create mode 100644 original_examples/samples/Circles/b_i.png create mode 100644 original_examples/samples/Circles/b_quarter.png create mode 100644 original_examples/samples/Circles/data.xml create mode 100644 original_examples/samples/Circles/w.png create mode 100644 original_examples/samples/Circles/w_half.png create mode 100644 original_examples/samples/Circles/w_i.png create mode 100644 original_examples/samples/Circles/w_quarter.png create mode 100644 original_examples/samples/Circuit/bridge.png create mode 100644 original_examples/samples/Circuit/component.png create mode 100644 original_examples/samples/Circuit/connection.png create mode 100644 original_examples/samples/Circuit/corner.png create mode 100644 original_examples/samples/Circuit/data.xml create mode 100644 original_examples/samples/Circuit/dskew.png create mode 100644 original_examples/samples/Circuit/skew.png create mode 100644 original_examples/samples/Circuit/substrate.png create mode 100644 original_examples/samples/Circuit/t.png create mode 100644 original_examples/samples/Circuit/track.png create mode 100644 original_examples/samples/Circuit/transition.png create mode 100644 original_examples/samples/Circuit/turn.png create mode 100644 original_examples/samples/Circuit/viad.png create mode 100644 original_examples/samples/Circuit/vias.png create mode 100644 original_examples/samples/Circuit/wire.png create mode 100644 original_examples/samples/City.png create mode 100644 original_examples/samples/Colored City.png create mode 100644 original_examples/samples/Dungeon.png create mode 100644 original_examples/samples/Fabric.png create mode 100644 original_examples/samples/Flowers.png create mode 100644 original_examples/samples/Forest.png create mode 100644 original_examples/samples/Hogs.png create mode 100644 original_examples/samples/Knot.png create mode 100644 original_examples/samples/Knots/corner.png create mode 100644 original_examples/samples/Knots/cross.png create mode 100644 original_examples/samples/Knots/data.xml create mode 100644 original_examples/samples/Knots/empty.png create mode 100644 original_examples/samples/Knots/line.png create mode 100644 original_examples/samples/Knots/t.png create mode 100644 original_examples/samples/Lake.png create mode 100644 original_examples/samples/Less Rooms.png create mode 100644 original_examples/samples/Link 2.png create mode 100644 original_examples/samples/Link.png create mode 100644 original_examples/samples/Magic Office.png create mode 100644 original_examples/samples/Maze.png create mode 100644 original_examples/samples/Mazelike.png create mode 100644 original_examples/samples/More Flowers.png create mode 100644 original_examples/samples/Mountains.png create mode 100644 original_examples/samples/Nested.png create mode 100644 original_examples/samples/Office 2.png create mode 100644 original_examples/samples/Office.png create mode 100644 original_examples/samples/Paths.png create mode 100644 original_examples/samples/Platformer.png create mode 100644 original_examples/samples/Qud.png create mode 100644 original_examples/samples/Red Dot.png create mode 100644 original_examples/samples/Red Maze.png create mode 100644 original_examples/samples/Rooms.png create mode 100644 original_examples/samples/Rooms/bend.png create mode 100644 original_examples/samples/Rooms/corner.png create mode 100644 original_examples/samples/Rooms/corridor.png create mode 100644 original_examples/samples/Rooms/data.xml create mode 100644 original_examples/samples/Rooms/door.png create mode 100644 original_examples/samples/Rooms/empty.png create mode 100644 original_examples/samples/Rooms/side.png create mode 100644 original_examples/samples/Rooms/t.png create mode 100644 original_examples/samples/Rooms/turn.png create mode 100644 original_examples/samples/Rooms/wall.png create mode 100644 original_examples/samples/Rule 126.png create mode 100644 original_examples/samples/Scaled Maze.png create mode 100644 original_examples/samples/Sewers.png create mode 100644 original_examples/samples/Simple Knot.png create mode 100644 original_examples/samples/Simple Maze.png create mode 100644 original_examples/samples/Simple Wall.png create mode 100644 original_examples/samples/Skew 1.png create mode 100644 original_examples/samples/Skew 2.png create mode 100644 original_examples/samples/Skyline 2.png create mode 100644 original_examples/samples/Skyline.png create mode 100644 original_examples/samples/Smile City.png create mode 100644 original_examples/samples/Spirals.png create mode 100644 original_examples/samples/Summer/cliff 0.png create mode 100644 original_examples/samples/Summer/cliff 1.png create mode 100644 original_examples/samples/Summer/cliff 2.png create mode 100644 original_examples/samples/Summer/cliff 3.png create mode 100644 original_examples/samples/Summer/cliffcorner 0.png create mode 100644 original_examples/samples/Summer/cliffcorner 1.png create mode 100644 original_examples/samples/Summer/cliffcorner 2.png create mode 100644 original_examples/samples/Summer/cliffcorner 3.png create mode 100644 original_examples/samples/Summer/cliffturn 0.png create mode 100644 original_examples/samples/Summer/cliffturn 1.png create mode 100644 original_examples/samples/Summer/cliffturn 2.png create mode 100644 original_examples/samples/Summer/cliffturn 3.png create mode 100644 original_examples/samples/Summer/data.xml create mode 100644 original_examples/samples/Summer/grass 0.png create mode 100644 original_examples/samples/Summer/grasscorner 0.png create mode 100644 original_examples/samples/Summer/grasscorner 1.png create mode 100644 original_examples/samples/Summer/grasscorner 2.png create mode 100644 original_examples/samples/Summer/grasscorner 3.png create mode 100644 original_examples/samples/Summer/road 0.png create mode 100644 original_examples/samples/Summer/road 1.png create mode 100644 original_examples/samples/Summer/road 2.png create mode 100644 original_examples/samples/Summer/road 3.png create mode 100644 original_examples/samples/Summer/roadturn 0.png create mode 100644 original_examples/samples/Summer/roadturn 1.png create mode 100644 original_examples/samples/Summer/roadturn 2.png create mode 100644 original_examples/samples/Summer/roadturn 3.png create mode 100644 original_examples/samples/Summer/water_a 0.png create mode 100644 original_examples/samples/Summer/water_b 0.png create mode 100644 original_examples/samples/Summer/water_c 0.png create mode 100644 original_examples/samples/Summer/watercorner 0.png create mode 100644 original_examples/samples/Summer/watercorner 1.png create mode 100644 original_examples/samples/Summer/watercorner 2.png create mode 100644 original_examples/samples/Summer/watercorner 3.png create mode 100644 original_examples/samples/Summer/waterside 0.png create mode 100644 original_examples/samples/Summer/waterside 1.png create mode 100644 original_examples/samples/Summer/waterside 2.png create mode 100644 original_examples/samples/Summer/waterside 3.png create mode 100644 original_examples/samples/Summer/waterturn 0.png create mode 100644 original_examples/samples/Summer/waterturn 1.png create mode 100644 original_examples/samples/Summer/waterturn 2.png create mode 100644 original_examples/samples/Summer/waterturn 3.png create mode 100644 original_examples/samples/Town.png create mode 100644 original_examples/samples/Trick Knot.png create mode 100644 original_examples/samples/Village.png create mode 100644 original_examples/samples/Water.png create mode 100644 original_examples/src/include/color.hpp create mode 100644 original_examples/src/include/external/rapidxml.hpp create mode 100644 original_examples/src/include/external/stb_image.h create mode 100644 original_examples/src/include/external/stb_image_write.h create mode 100644 original_examples/src/include/image.hpp create mode 100644 original_examples/src/include/rapidxml_utils.hpp create mode 100644 original_examples/src/include/utils.hpp create mode 100644 original_examples/src/lib/main.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e9ffb83 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +engine +pandemonium_engine +modules/* +logs/* + +*.d +*.o +*.meta +game/.import/** +game/.prop_tool_temp/** +.sconsign.dblite +.DS_Store + +export/** +release/** + +.vs/* +.kdev4/* +.vscode/* + +TestRWTextures + +_build/* +_binaries/* +game/android/build/* + +*.blend1 +.dir-locals.el + +build.config + +__pycache__/* \ No newline at end of file diff --git a/HEADS b/HEADS new file mode 100644 index 0000000..4f315f5 --- /dev/null +++ b/HEADS @@ -0,0 +1 @@ +{"engine": {"3.2": "94a0fc47f7b4e90f8973f9adbfd3312579ed2825", "master": "8c73e813134001e575b6f59e3b0100471c007410", "3.x": "c4864a0e5f73a375259503ea1485794a6aad6df7"}, "world_generator": {"master": "260c430f11b0b591eaf4714516419aa327d2842c"}, "entity_spell_system": {"master": "3536f01bacf5f54cefb32b768cd020a1f94d0ade"}, "ui_extensions": {"master": "80a3b96fc56991a0f88a1d441ed1e3cebaf3307a"}, "voxelman": {"master": "65485930a20f65844d496b4ba47dec5b6ed70b91"}, "texture_packer": {"master": "ae4d222fbaade063ed6f0bc9f3aaa53df68a7fed"}, "fastnoise": {"master": "46bb1f610bfb7171613b5c708d312bcf94e89356"}, "mesh_data_resource": {"master": "a062d871d49d954c5466b9de54b4075cb61cbef4"}, "procedural_animations": {"master": "f8aae42bf06b3936cc6bd24cb18e1c3ec9f78f4f"}, "ess_data": {"master": "3bd637fdd3304b64a18287a49a6b7387acf2f5de"}, "props": {"master": "983090d21a08ebed30a5ce06681269819ab12e48"}, "mesh_utils": {"master": "b52a261c31f04fad624e5cfbcdcc4a45d61136da"}, "broken_seals_module": {"master": "52c5a81350db1c29d375c63d95010260911ec034"}, "thread_pool": {"master": "0917511d04bb1aa308385b63ec88d3c182990628"}, "terraman": {"master": "c72d8fc03295588fc18c5168ce351bd0c321ec5f"}, "pandemonium_engine": {"master": "d7f833ee75780bec0d10ca792ca3f7ebbfa36faf"}} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9f4a035 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2022 Péter Magyar +Copyright (c) 2018-2019 Mathieu Fehr and Nathanaël Courant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f1b4757 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +all: + scons bels -j5 + +e: + scons belsE -j5 + +t: + scons belsT -j5 + +v: + scons belsV -j5 + +W: + scons belsW -j5 + +p: + scons belsP -j5 + +m: + scons belsM -j5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..dbe75d9 --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# fast-wfc + +https://github.com/math-fehr/fast-wfc + +An implementation of [Wave Function Collapse](https://github.com/mxgmn/WaveFunctionCollapse) with a focus on performance. +It was called fast-wfc because at the time it introduced optimizations improving the execution time by an order of magnitude. + +[Rust bindings](https://github.com/rickyhan/fastwfc-rs) + +# Requirements + +You need a C++-17 compatible compiler, and CMake installed. + +# Install the library + +``` +git clone https://github.com/math-fehr/fast-wfc && cd fast-wfc/ +cmake . +make install +``` + +will install the library `fastwfc` and `fastwfc_static` using CMake: + +# Run the examples + +``` +cd example/ +cmake . +make +./wfc_demo +``` + +will execute WFC on the examples defined in `example/samples.xml`, and will put the results in `example/results`. + +# Third-parties library + +The files in `example/src/include/external/` come from: +* RapidXML [https://github.com/dwd/rapidxml](https://github.com/dwd/rapidxml) +* stb Library [https://github.com/nothings/stb](https://github.com/nothings/stb) + +# Image samples + +The image samples come from [https://github.com/mxgmn/WaveFunctionCollapse](https://github.com/mxgmn/WaveFunctionCollapse) + +# Licence + +Copyright (c) 2018-2019 Mathieu Fehr and Nathanaël Courant. + +MIT License, see `LICENSE` for further details. diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000..4abba6b --- /dev/null +++ b/SConstruct @@ -0,0 +1,652 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (c) 2019-2021 Péter Magyar +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +EnsureSConsVersion(0, 98, 1) + +import sys +import os +import subprocess +import json +import shutil +import traceback + +import module_config + +repository_index = 0 +module_clone_path = '/modules/' +clone_command = 'git clone {0} {1}' + +visual_studio_call_vcvarsall = False +visual_studio_vcvarsall_path = 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvarsall.bat' +visual_studio_arch = 'amd64' + +exports = { + 'global': [], + 'linux': [], + 'windows': [], + 'android': [], + 'javascript': [], + 'osx': [], + 'ios': [], + 'server': [], +} + +additional_commands = { + 'global': [], + 'linux': [], + 'windows': [], + 'android': [], + 'javascript': [], + 'osx': [], + 'ios': [], + 'server': [], +} + +target_commits = {} + +def onerror(func, path, exc_info): + """ + https://stackoverflow.com/questions/2656322/shutil-rmtree-fails-on-windows-with-access-is-denied + + Because Windows. + + Error handler for ``shutil.rmtree``. + + If the error is due to an access error (read only file) + it attempts to add write permission and then retries. + + If the error is for another reason it re-raises the error. + + Usage : ``shutil.rmtree(path, onerror=onerror)`` + """ + import stat + if not os.access(path, os.W_OK): + # Is the error an access error ? + os.chmod(path, stat.S_IWUSR) + func(path) + else: + raise + +def load_target_commits_array(): + global target_commits + + if os.path.isfile('./HEADS'): + with open('./HEADS', 'r') as infile: + target_commits = json.load(infile) + else: + target_commits = {} + +def save_target_commits_array(): + with open('./HEADS', 'w') as outfile: + json.dump(target_commits, outfile) + +def update_repository(data, clone_path, branch = 'master'): + cwd = os.getcwd() + + full_path = cwd + clone_path + data[1] + '/' + + if not os.path.isdir(full_path): + os.chdir(cwd + clone_path) + + subprocess.call(clone_command.format(data[0][repository_index], data[1]), shell=True) + + os.chdir(full_path) + + subprocess.call('git reset', shell=True) + subprocess.call('git reset --hard', shell=True) + subprocess.call('git clean -f -d', shell=True) + subprocess.call('git checkout -B ' + branch + ' origin/' + branch, shell=True) + subprocess.call('git reset', shell=True) + subprocess.call('git reset --hard', shell=True) + subprocess.call('git clean -f -d', shell=True) + subprocess.call('git pull origin ' + branch, shell=True) + + process = subprocess.Popen('git rev-parse HEAD', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + output = process.communicate()[0].decode().strip() + + if data[1] not in target_commits: + target_commits[data[1]] = {} + + target_commits[data[1]][branch] = output + + os.chdir(cwd) + +def setup_repository(data, clone_path, branch = 'master'): + cwd = os.getcwd() + + full_path = cwd + clone_path + data[1] + '/' + + if not os.path.isdir(full_path): + os.chdir(cwd + clone_path) + + subprocess.call(clone_command.format(data[0][repository_index], data[1]), shell=True) + + os.chdir(full_path) + + subprocess.call('git reset', shell=True) + subprocess.call('git reset --hard', shell=True) + subprocess.call('git clean -f -d', shell=True) + subprocess.call('git checkout -B ' + branch + ' origin/' + branch, shell=True) + subprocess.call('git pull origin ' + branch, shell=True) + subprocess.call('git reset', shell=True) + subprocess.call('git reset --hard', shell=True) + + if data[1] in target_commits: + target = target_commits[data[1]][branch] + + subprocess.call('git checkout -B ' + branch + ' ' + target, shell=True) + subprocess.call('git clean -f -d', shell=True) + subprocess.call('git reset', shell=True) + subprocess.call('git reset --hard', shell=True) + + os.chdir(cwd) + +def copy_repository(data, target_folder, clone_path): + copytree(os.path.abspath(clone_path + data[1] + '/' + data[2]), os.path.abspath(target_folder + data[1])) + +def copytree(src, dst): + for item in os.listdir(src): + sp = os.path.join(src, item) + dp = os.path.join(dst, item) + + if os.path.isdir(sp): + if os.path.isdir(dp): + shutil.rmtree(dp, onerror=onerror) + + shutil.copytree(sp, dp) + else: + if not os.path.isdir(dst): + os.makedirs(dst) + + shutil.copy2(sp, dp) + +def validate_repository_origin(data, clone_path, branch = 'master'): + full_path = os.path.abspath(clone_path) + + if not os.path.isdir(full_path): + return + + cwd = os.getcwd() + os.chdir(full_path) + + res = subprocess.run('git remote -v', shell=True, capture_output=True) + + resstr = res.stdout.decode('ascii') + resarr = resstr.split("\n") + res_orig = [] + + for l in resarr: + if "origin" in l: + res_orig.append(l) + + if len(res_orig) == 0: + print("The repository " + clone_path + " does not seem to have an origin remote. Adding it.") + + subprocess.call('git remote add origin ' + data[0][repository_index], shell=True) + + os.chdir(cwd) + + return + + for l in data[0]: + for ll in res_orig: + if l in ll: + os.chdir(cwd) + + return + + rind = 0 + + if 'git@' in res_orig[0]: + rind = 1 + + subprocess.call('git remote remove origin', shell=True) + subprocess.call('git remote add origin ' + data[0][rind], shell=True) + subprocess.call('git pull origin', shell=True) + subprocess.call('git checkout origin/' + branch, shell=True) + + print('Updated git remote origin in ' + clone_path) + + os.chdir(cwd) + +def remove_repository(data, target_folder): + folder = os.path.abspath(target_folder + data[1]) + + if os.path.isdir(folder): + shutil.rmtree(folder) + +def update_engine(): + validate_repository_origin(module_config.engine_repository, './pandemonium_engine/', module_config.pandemonium_branch) + update_repository(module_config.engine_repository, '/', module_config.pandemonium_branch) + +def update_modules(): + for rep in module_config.module_repositories: + update_repository(rep, module_clone_path) + copy_repository(rep, './pandemonium_engine/modules/', '.' + module_clone_path) + +def update_addons(): + for rep in module_config.addon_repositories: + update_repository(rep, module_clone_path) + copy_repository(rep, './game/addons/', '.' + module_clone_path) + +def update_addons_third_party_addons(): + for rep in module_config.third_party_addon_repositories: + update_repository(rep, module_clone_path) + copy_repository(rep, './game/addons/', '.' + module_clone_path) + +def update_all(): + update_engine() + update_modules() + update_addons() + update_addons_third_party_addons() + + save_target_commits_array() + + +def setup_engine(): + validate_repository_origin(module_config.engine_repository, './pandemonium_engine/', module_config.pandemonium_branch) + setup_repository(module_config.engine_repository, '/', module_config.pandemonium_branch) + +def setup_modules(): + for rep in module_config.module_repositories: + setup_repository(rep, module_clone_path) + copy_repository(rep, './pandemonium_engine/modules/', '.' + module_clone_path) + + for rep in module_config.removed_modules: + remove_repository(rep, './pandemonium_engine/modules/') + + +def setup_addons(): + for rep in module_config.addon_repositories: + setup_repository(rep, module_clone_path) + copy_repository(rep, './game/addons/', '.' + module_clone_path) + +def setup_addons_third_party_addons(): + for rep in module_config.third_party_addon_repositories: + setup_repository(rep, module_clone_path) + copy_repository(rep, './game/addons/', '.' + module_clone_path) + +def setup_all(): + setup_engine() + setup_modules() + setup_addons() + setup_addons_third_party_addons() + +def format_path(path): + if 'win' in sys.platform: + path = path.replace('/', '\\') + path = path.replace('~', '%userprofile%') + + return path + +def get_exports_for(platform): + export_command = 'export ' + command_separator = ';' + + if 'win' in sys.platform: + command_separator = '&' + export_command = 'set ' + + command = '' + + for p in exports[platform]: + command += export_command + p + command_separator + + return command + +def get_additional_commands_for(platform): + command_separator = ';' + + if 'win' in sys.platform: + command_separator = '&' + + command = '' + + for p in additional_commands[platform]: + command += p + command_separator + + return command + + + +def parse_config(): + global visual_studio_vcvarsall_path + global visual_studio_arch + global visual_studio_call_vcvarsall + global exports + + if not os.path.isfile('build.config'): + return + + with open('build.config', 'r') as f: + + for line in f: + ls = line.strip() + if ls == '' or ls.startswith('#'): + continue + + words = line.split() + + if (len(words) < 2): + print('This build.config line is malformed, and got ignored: ' + ls) + continue + + if words[0] == 'visual_studio_vcvarsall_path': + visual_studio_vcvarsall_path = format_path(ls[29:]) + elif words[0] == 'visual_studio_arch': + visual_studio_arch = format_path(ls[19:]) + elif words[0] == 'visual_studio_call_vcvarsall': + visual_studio_call_vcvarsall = words[1].lower() in [ 'true', '1', 't', 'y', 'yes' ] + elif words[0] == 'export': + if (len(words) < 3) or not words[1] in exports: + print('This build.config line is malformed, and got ignored: ' + ls) + continue + + export_path = format_path(ls[8 + len(words[1]):]) + + exports[words[1]].append(export_path) + elif words[0] == 'run': + if (len(words) < 3) or not words[1] in additional_commands: + print('This build.config line is malformed, and got ignored: ' + ls) + continue + + final_cmd = format_path(ls[5 + len(words[1]):]) + + additional_commands[words[1]].append(final_cmd) + +parse_config() + +env = Environment() + +if len(sys.argv) > 1: + + arg = sys.argv[1] + + arg_split = arg.split('_') + arg = arg_split[0] + arg_split = arg_split[1:] + + if arg[0] == 'b': + build_string = get_exports_for('global') + get_additional_commands_for('global') + 'scons ' + + build_string += 'tools=' + if 'e' in arg: + build_string += 'yes' + else: + build_string += 'no' + build_string += ' ' + + build_string += 'target=' + if 'r' in arg: + build_string += 'release' + elif 'd' in arg: + build_string += 'debug' + else: + build_string += 'release_debug' + build_string += ' ' + + build_string += 'custom_modules_shared=' + if 's' in arg: + build_string += 'yes' + else: + build_string += 'no' + build_string += ' ' + + if 'm' in arg: + build_string += 'use_mingw=yes' + else: + if 'win' in sys.platform and visual_studio_call_vcvarsall: + build_string = 'call "{0}" {1}&'.format(visual_studio_vcvarsall_path, visual_studio_arch) + build_string + + if 'o' in arg: + build_string += 'use_llvm=yes' + + if 'v' in arg: + build_string += 'vsproj=yes' + + for i in range(2, len(sys.argv)): + build_string += ' ' + sys.argv[i] + ' ' + + if 'slim' in arg_split: + build_string += module_config.slim_args + build_string += ' ' + + if 'latomic' in arg_split: + build_string += 'LINKFLAGS="-latomic"' + build_string += ' ' + + if 'strip' in arg_split: + build_string += 'debug_symbols=no' + build_string += ' ' + + if 'threads' in arg_split: + build_string += 'threads_enabled=yes' + build_string += ' ' + + if 'c' in arg: + build_string += 'compiledb=yes' + build_string += ' ' + + target = ' ' + + if 'E' in arg: + target += 'bin/libess.x11.opt.tools.64.so' + elif 'T' in arg: + target += 'bin/libtexture_packer.x11.opt.tools.64.so' + elif 'V' in arg: + target += 'bin/libvoxelman.x11.opt.tools.64.so' + elif 'W' in arg: + target += 'bin/libworld_generator.x11.opt.tools.64.so' + elif 'P' in arg: + target += 'bin/libprocedural_animations.x11.opt.tools.64.so' + + cwd = os.getcwd() + full_path = cwd + '/pandemonium_engine/' + + if not os.path.isdir(full_path): + print('engine (pandemonium_engine) directory doesnt exists.') + exit() + + os.chdir(full_path) + + if 'l' in arg: + build_string += 'platform=x11' + + build_string = get_exports_for('linux') + get_additional_commands_for('linux') + build_string + target + + print('Running command: ' + build_string) + + subprocess.call(build_string, shell=True) + elif 'w' in arg: + build_string += 'platform=windows' + + build_string = get_exports_for('windows') + get_additional_commands_for('windows') + build_string + + print('Running command: ' + build_string) + + subprocess.call(build_string, shell=True) + elif 'a' in arg: + build_string += 'platform=android' + + build_string = get_exports_for('android') + get_additional_commands_for('android') + build_string + + print('Running command: ' + build_string + ' android_arch=armv7') + subprocess.call(build_string + ' android_arch=armv7', shell=True) + print('Running command: ' + build_string + ' android_arch=arm64v8') + subprocess.call(build_string + ' android_arch=arm64v8', shell=True) + print('Running command: ' + build_string + ' android_arch=x86') + subprocess.call(build_string + ' android_arch=x86', shell=True) + + os.chdir(full_path + 'platform/android/java/') + + if 'e' in arg: #editor + print('Running command: ' + get_exports_for('global') + get_additional_commands_for('global') + get_exports_for('android') + get_additional_commands_for('android') + './gradlew generatePandemoniumEditor') + subprocess.call(get_exports_for('global') + get_additional_commands_for('global') + get_exports_for('android') + get_additional_commands_for('android') + './gradlew generatePandemoniumEditor', shell=True) + else: #normal templates + print('Running command: ' + get_exports_for('global') + get_additional_commands_for('global') + get_exports_for('android') + get_additional_commands_for('android') + './gradlew generatePandemoniumTemplates') + subprocess.call(get_exports_for('global') + get_additional_commands_for('global') + get_exports_for('android') + get_additional_commands_for('android') + './gradlew generatePandemoniumTemplates', shell=True) + elif 'j' in arg: + build_string += 'platform=javascript' + + build_string = get_exports_for('javascript') + get_additional_commands_for('javascript') + build_string + + print('Running command: ' + build_string) + subprocess.call(build_string, shell=True) + elif 'i' in arg: + build_string += 'platform=iphone' + + print('Running command: ' + build_string) + subprocess.call(build_string, shell=True) + + #print('Running command: ' + build_string + " arch=arm") + #subprocess.call(build_string + ' arch=arm', shell=True) + #print('Running command: ' + build_string + " arch=arm64") + #subprocess.call(build_string + ' arch=arm64', shell=True) + #print('Running command: ' + build_string + " arch=x86_64") + #subprocess.call(build_string + ' arch=x86_64', shell=True) + elif 'x' in arg: + build_string += 'platform=osx' + + build_string = get_exports_for('osx') + get_additional_commands_for('osx') + build_string + target + + print('Running command: ' + build_string) + subprocess.call(build_string, shell=True) + elif 'h' in arg: + #headless + build_string += 'platform=server' + + build_string = get_exports_for('server') + get_additional_commands_for('server') + build_string + + print('Running command: ' + build_string) + + subprocess.call(build_string, shell=True) + + else: + print('No platform specified') + exit() + + exit() +# elif arg[0] == 'p': +# if arg == 'p': +# print("Applies a patch. No Patches right now.Append s for the skeleton editor patch. For example: ps ") +# exit() +# +# cwd = os.getcwd() +# full_path = cwd + '/pandemonium_engine/' +# +# if not os.path.isdir(full_path): +# print('engine (pandemonium_engine) directory does not exists.') +# exit() +# +# os.chdir(full_path) +# +# #apply the patch to just the working directory, without creating a commit +# +# if 's' in arg: +# subprocess.call('git apply --index ../patches/custom_skeleton_3d_editor_plugin.patch', shell=True) +# +# #unstage all files +# subprocess.call('git reset', shell=True) +# +# vman_full_path = cwd + '/pandemonium_engine/modules/voxelman/' +# +# #also patch voxelman as the plugin changes forward_spatial_gui_input's definition +# if os.path.isdir(vman_full_path): +# os.chdir(vman_full_path) +# +# subprocess.call('git apply --index ../../../patches/fix-voxel-editor-after-the-skeleton-editor-patch.patch', shell=True) +# +# #unstage all files +# subprocess.call('git reset', shell=True) +# else: +# print('Voxelman directory does not exists, skipping patch.') +# +# exit() + +opts = Variables(args=ARGUMENTS) + +opts.Add('a', 'What to do', '') +opts.Add(EnumVariable('action', 'What to do', 'setup', ('setup', 'update'))) +opts.Add('t', 'Action target', '') +opts.Add(EnumVariable('target', 'Action target', 'all', ('all', 'engine', 'modules', 'all_addons', 'addons', 'third_party_addons'))) +opts.Add(EnumVariable('repository_type', 'Type of repositories to clone from first', 'http', ('http', 'ssh'))) + +opts.Update(env) +Help(opts.GenerateHelpText(env)) + +load_target_commits_array() + +rt = env['repository_type'] + +if rt == 'ssh': + repository_index = 1 + +action = env['action'] +target = env['target'] + +if env['a']: + action = env['a'] + +if env['t']: + target = env['t'] + +if not os.path.isdir('./modules'): + os.mkdir('./modules') + +if 'm' in action: + pandemonium_branch = 'master' + +if 'setup' in action or action[0] == 's': + if target == 'all': + setup_all() + elif target == 'engine': + setup_engine() + elif target == 'modules': + setup_modules() + elif target == 'all_addons': + setup_addons() + setup_addons_third_party_addons() + elif target == 'addons': + setup_addons() + elif target == 'third_party_addons': + setup_addons_third_party_addons() +elif 'update' in action or action[0] == 'u': + if target == 'all': + update_all() + elif target == 'engine': + update_engine() + save_target_commits_array() + elif target == 'modules': + update_modules() + save_target_commits_array() + elif target == 'all_addons': + update_addons() + update_addons_third_party_addons() + save_target_commits_array() + elif target == 'addons': + update_addons() + save_target_commits_array() + elif target == 'third_party_addons': + update_addons_third_party_addons() + save_target_commits_array() + diff --git a/build.config.example b/build.config.example new file mode 100644 index 0000000..f5ef65d --- /dev/null +++ b/build.config.example @@ -0,0 +1,45 @@ +# Copyright (c) 2019-2021 Péter Magyar +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Rename this file to build.config to use it + +# Lines starting with # are comments. (Only works at the start of the line!) + +# Note: +# ~ will be converted to %userprofile% on windows +# / will be converted to \ on windows +# so you don't have to worry about it + +# Visual studio related setup: +visual_studio_call_vcvarsall True +visual_studio_vcvarsall_path C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Auxiliary/Build/vcvarsall.bat +visual_studio_arch amd64 + +# You can export variables with the export keyword +# You can run commands with the run keywords +# +# available export/run targets: global, linux, windows, android, javascript + +export global SCONS_CACHE=~/.scons_cache +export global SCONS_CACHE_LIMIT=5000 + +export android ANDROID_HOME=~/SDKs/Android/SDK + +run javascript source ~/SDKs/emsdk/emsdk_env.sh diff --git a/editor.bat b/editor.bat new file mode 100644 index 0000000..6259159 --- /dev/null +++ b/editor.bat @@ -0,0 +1,6 @@ + +copy "pandemonium_engine\bin\pandemonium.windows.opt.tools.64.exe" "pandemonium_engine\bin\run_pandemonium.windows.opt.tools.64.exe" /y +copy "pandemonium_engine\bin\pandemonium.windows.opt.tools.64.pdb" "pandemonium_engine\bin\run_pandemonium.windows.opt.tools.64.pdb" /y +copy "pandemonium_engine\bin\pandemonium.windows.opt.tools.64.exp" "pandemonium_engine\bin\run_pandemonium.windows.opt.tools.64.exp" /y + +cmd /c pandemonium_engine\bin\run_pandemonium.windows.opt.tools.64.exe \ No newline at end of file diff --git a/editor.sh b/editor.sh new file mode 100755 index 0000000..1aec724 --- /dev/null +++ b/editor.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +cp -u ./pandemonium_engine/bin/pandemonium.x11.opt.tools.64 ./pandemonium_engine/bin/run.pandemonium.x11.opt.tools.64 + +export LD_LIBRARY_PATH=`pwd`/pandemonium_engine/bin/ +./pandemonium_engine/bin/run.pandemonium.x11.opt.tools.64 -v diff --git a/ged.sh b/ged.sh new file mode 100755 index 0000000..51ef2eb --- /dev/null +++ b/ged.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +cp -u ./pandemonium_engine/bin/pandemonium.x11.opt.tools.64 ./pandemonium_engine/bin/run.pandemonium.x11.opt.tools.64 + +export LD_LIBRARY_PATH=`pwd`/pandemonium_engine/bin/ +./pandemonium_engine/bin/run.pandemonium.x11.opt.tools.64 -e --path ./game/ diff --git a/lged.sh b/lged.sh new file mode 100755 index 0000000..8d6c525 --- /dev/null +++ b/lged.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +cp -u ./pandemonium_engine/bin/pandemonium.x11.opt.tools.64.llvm ./pandemonium_engine/bin/run.pandemonium.x11.opt.tools.64.llvm + +export LD_LIBRARY_PATH=`pwd`/pandemonium_engine/bin/ +./pandemonium_engine/bin/run.pandemonium.x11.opt.tools.64.llvm -e --path ./game/ diff --git a/module_config.py b/module_config.py new file mode 100644 index 0000000..997e7d5 --- /dev/null +++ b/module_config.py @@ -0,0 +1,18 @@ + +pandemonium_branch = 'master' + +engine_repository = [ ['https://github.com/Relintai/pandemonium_engine.git', 'git@github.com:Relintai/pandemonium_engine.git'], 'pandemonium_engine', '' ] + +module_repositories = [ +] + +removed_modules = [ +] + +addon_repositories = [ +] + +third_party_addon_repositories = [ +] + +slim_args = 'module_webm_enabled=no module_arkit_enabled=no module_visual_script_enabled=no module_gdnative_enabled=no module_mobile_vr_enabled=no module_theora_enabled=no module_xatlas_unwrap_enabled=no' diff --git a/original_examples/.vscode/settings.json b/original_examples/.vscode/settings.json new file mode 100644 index 0000000..e2c18d1 --- /dev/null +++ b/original_examples/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "ostream": "cpp" + } +} \ No newline at end of file diff --git a/original_examples/CMakeLists.txt b/original_examples/CMakeLists.txt new file mode 100644 index 0000000..aa65c91 --- /dev/null +++ b/original_examples/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.9) +project(wfc_demo LANGUAGES CXX) + +make_directory(results) + +set(CMAKE_CXX_STANDARD 17) +set(DEFAULT_BUILD_TYPE "Release") + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.") + set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE) +endif() + +find_library( FASTWFC_LIB + NAMES + fastwfc_static + ) + +add_executable(${PROJECT_NAME} src/lib/main.cpp) +target_link_libraries(wfc_demo ${FASTWFC_LIB}) + +target_include_directories(${PROJECT_NAME} PUBLIC + $) diff --git a/original_examples/samples.xml b/original_examples/samples.xml new file mode 100644 index 0000000..c280657 --- /dev/null +++ b/original_examples/samples.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/original_examples/samples/3Bricks.png b/original_examples/samples/3Bricks.png new file mode 100644 index 0000000000000000000000000000000000000000..33205e56fa70e421a3c97c1ad832c6fcdb3e984a GIT binary patch literal 351 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvg8-ipS8YLta4m+ZUO+xkphW4` zT%bbE0*}aI1_o{+5N5n|x9$&6@T#YaV~EDY+=&-?k0|gs3#)Z(cHH!TLi+5wIqTZ5 zu<@MGS9?@G=dNts&hm&GaXa!Jb7?15rLDgp!5NdJQNf&EB4}fH=g|{}?nwc0%DaD_ zu1ajtIk(6&Ih)hDJvW@|!J`{L54lQrG2P{7Z1PEwNHSYn?PSt&SxU3S_yONl^W&2b z*E}`c&EG7=AAQdztoL|ktiF0E?#Q{qzExIzGjrX86j1PZy85}S Ib4q9e0GqFOGynhq literal 0 HcmV?d00001 diff --git a/original_examples/samples/Angular.png b/original_examples/samples/Angular.png new file mode 100644 index 0000000000000000000000000000000000000000..7b8efd64a042f088ca8e64fd1998bb18dcb19361 GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sDEfH31!Z9ZwBpogc6V~9p@@*jQ{9v7xHU6PWL3w2l+G!L)* zv9^b6%JBmVf1dC~7z$7E7g2~cJQ0=B!`*PV=bc-LL$&$gxsDtSa~z#`j0_kU-u=~L U-ROVr9MDV#Pgg&ebxsLQ0R2KT`2YX_ literal 0 HcmV?d00001 diff --git a/original_examples/samples/Castle/bridge.png b/original_examples/samples/Castle/bridge.png new file mode 100644 index 0000000000000000000000000000000000000000..737c692ca6f759e70cccc120eb483463db4eb023 GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^>>$j+1SGu;4zvI%&H|6fVg?3oArNM~bhqvgP|(=Z z#W93qX7Zdu7n8^LQrT1toIR(1{O@VU#&h7uf8k{c%)(-ZF^hC~u5X-i+UT>n^)hLO Y{R??dWOT%=0cvOPboFyt=akR{0H@9+H2?qr literal 0 HcmV?d00001 diff --git a/original_examples/samples/Castle/data.xml b/original_examples/samples/Castle/data.xml new file mode 100644 index 0000000..c4fc3f2 --- /dev/null +++ b/original_examples/samples/Castle/data.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/original_examples/samples/Castle/ground.png b/original_examples/samples/Castle/ground.png new file mode 100644 index 0000000000000000000000000000000000000000..8eff3f28ccd8df9c2e3bc14aff61efb559ff1786 GIT binary patch literal 98 zcmeAS@N?(olHy`uVBq!ia0vp^>>$j+1SGu;4zvI%&H|6fVg?3oArNM~bhqvgP*B9v r#W93qX7Zdumnn?Q28mo3V?`JqWHZ)3j^vaA$}@Pn`njxgN@xNAe2x{u literal 0 HcmV?d00001 diff --git a/original_examples/samples/Castle/river.png b/original_examples/samples/Castle/river.png new file mode 100644 index 0000000000000000000000000000000000000000..5c5f5f6d5327b116e736e756c96d9d6290022db6 GIT binary patch literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^>>$j+1SGu;4zvI%&H|6fVg?3oArNM~bhqvgP*B>_ y#W93qX7Zdu7n8^LQrT1toIR&^GD>$j+1SGu;4zvI%&H|6fVg?3oArNM~bhqvgP*C5~ z#W93qX7Zdu7n8^LQrT1toIR&^GBT&!+1=whrLmE5`wJe`*f&`hRU#&=ZQIOvzm(Ho T>gdsapjHM?S3j3^P6>$j+1SGu;4zvI%&H|6fVg?3oArNM~bhqvgP*BCw z#W93qX7Zdumnn^nim~ranL*(28Sh0rJUl);HyCPN89O;y>U|_xZUWUac)I$ztaD0e F0ss^v8e{+f literal 0 HcmV?d00001 diff --git a/original_examples/samples/Castle/roadturn.png b/original_examples/samples/Castle/roadturn.png new file mode 100644 index 0000000000000000000000000000000000000000..77a0f33daf5936315090aa1ba74599feace9d20d GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^>>$j+1SGu;4zvI%&H|6fVg?3oArNM~bhqvgP|(=Z z#W93qX7Zdumnn^nim~ranL*(28Sh0rJUl);HyF63=+3A}0U< literal 0 HcmV?d00001 diff --git a/original_examples/samples/Castle/t.png b/original_examples/samples/Castle/t.png new file mode 100644 index 0000000000000000000000000000000000000000..77aa8e7ca3eb355536b20cd5edf0b52a31f585e3 GIT binary patch literal 124 zcmeAS@N?(olHy`uVBq!ia0vp^>>$j+1SGu;4zvI%&H|6fVg?3oArNM~bhqvgP*Bg) z#W93qX7Zdumnn?Q28mpT1_lQI{>$j+1SGu;4zvI%&H|6fVg?3oArNM~bhqvgP*B~| z#W93qW^w`;tXRLkeKHRZPtOS%j*Og~6c^z|)1uhc>$j+1SGu;4zvI%&H|6fVg?3oArNM~bhqvgP|(!V z#W93qX7Zdu7n8%!N^5IvnL)rgIr(vq@}eH&z7D(lbB{K#sKhQebbRvANx*FF6()u# X71@X7W>U&P0~kDA{an^LB{Ts5wFx7^ literal 0 HcmV?d00001 diff --git a/original_examples/samples/Castle/wallriver.png b/original_examples/samples/Castle/wallriver.png new file mode 100644 index 0000000000000000000000000000000000000000..a17adce1825ada4512861b98ce9186b601486881 GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^>>$j+1SGu;4zvI%&H|6fVg?3oArNM~bhqvgP|(fO z#W93qX7ZdumoGox>9DCNytL|_n0S%9&7$+yud0rKJD@KaozeTVkKe4vR8p00i_>zopr01~|{BLDyZ literal 0 HcmV?d00001 diff --git a/original_examples/samples/Castle/wallroad.png b/original_examples/samples/Castle/wallroad.png new file mode 100644 index 0000000000000000000000000000000000000000..a306816a0b168d390c36b90b59cf05013f9d942e GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^>>$j+1SGu;4zvI%&H|6fVg?3oArNM~bhqvgP|)4e z#W93qX7Zdu7n8%!N^5IvnL)rgIr(vq@}eH&z7D(lbB{K#sKhQe{P+LJffL6Y)_nV~ q&Zfqe!?0VUtazqE+QC+Z9ENl1QlUHkFFOV_lEKr}&t;ucLK6T>Sud6V literal 0 HcmV?d00001 diff --git a/original_examples/samples/Cat.png b/original_examples/samples/Cat.png new file mode 100644 index 0000000000000000000000000000000000000000..fc3f22088556e3e88b841ab6b7f3e4f6b8607d79 GIT binary patch literal 262 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9Q!3HFy+4N(86k~CayA#8@b22Z19F}xPUq=Rp zjs4tz5?O(K&H|6fVg?4jBOuH;Rhv&5C^*~G#WBRff9>Q(z7_)x=k|~L&G-M=!X4Uo z@ZF+)DT#u&3?Dry4v0&*7~!&HeSJq(c<*7hP1j= zwFUgY!von&US56o=|qPz!@|I|rhBudarahqwLa2d-`5uV_3^Sow(O@D5+A(m$@zWr zUeP|&|J*4|2V@qV(pP?PHZ4NfV9&pt8FK2!lvI6;>1s;*b3=DinK$vl=HlH+5aHgk=V~B|CbWZfwgH_7A1TP$t6;9}3;3@MxkS)TQ+H>}z?c^1A)~2BR0pkS1z zi(`n!#HAAt3Na|KxJ3W|f8J__l#}6G-H&0nCG3-)oepHF=Y8;ET9+h8BHNy{6}xpS zFYjK(H#_6NP46xBCl9K8J0fov^5)&zB?~jxFdSO*cuL7?k=OEH*K*!WR~M|%|Jehy Og~8L+&t;ucLK6T|nLNY* literal 0 HcmV?d00001 diff --git a/original_examples/samples/Chess.png b/original_examples/samples/Chess.png new file mode 100644 index 0000000000000000000000000000000000000000..090ce477b28e05dfdead9e967e6274c408062e91 GIT binary patch literal 106 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1SGw4HSYi^&H|6fVg?3oArNM~bhqvgP*BFx z#W93qX7Z2!|LvKXnbl4flP2^nwWajZGFfg82)bS6KltHedKoEwjx?6XckkBzvuOK0wL0xzb^aAbKTzCZ* zE;O+d*2K6r;s*I=Q3>NPnM`ILZ%3_2L46-p1x?IM-xkcQMx&8jb&e*YAPCfSI_(zy z8ME0;B}qa=N~vzq0*vEWEtg9o0?@5MfUDJtilVUAQm1PWl(n`f3Ied(?TE-2)0IF_ z+wB$r0k~W)!{LxRYC<4`!Qgy81E8v^0POdB$$niR5a%3#s;a22YXD_gE*1;=@}Q(V zNs{OD381cP0`Pvn0eJ6a+yCv5LTl~ydTp=-Kzad?WmyzO(&j(ygPCPAQ50oa)&PGB znpB?WaU2to*4h~JR}C{8W3<*pG@sA&JpZKsB4}>BUN7fdGbp8$*1Bb4X03Je{~KeR zb7fh!=xu=vPM+}Ir)e67A^qX=m1G!(X_|WP1ub*`4F3I)knJm_nE8Ic9}b7(@pw9& zZnxXx@gSlg2qu$Bk|gW(db8P#$K%hE_Iq@G3bmr+L$nw4f?m)IdcpU^4_jL$?daPE Q_y7O^07*qoM6N<$f_C)PPXGV_ literal 0 HcmV?d00001 diff --git a/original_examples/samples/Circles/b_i.png b/original_examples/samples/Circles/b_i.png new file mode 100644 index 0000000000000000000000000000000000000000..cc5e2057f6c9abd19982e2bf26fdb65c5faee7ca GIT binary patch literal 559 zcmV+~0?_@5P)!*LAZjBLJJthKQt; zx&#zzyBMmifU2qju-$Hz_xl105{4mws;a1I8URI6%w{wC zcA-?b@B8=r9YE7G1fZ^K07;UlZhu)r1-h<#KA&4G0Z_RBh@!}G9F^uj^@A~{D&sg# z6h$rYr$FmU)70}kA`(JKDgP?N7?V;8A&6)?ou+B}O8-TmU3femVHmcB;+zX1-jo<) zLWuVKODV%JEQ;cd{w|;jr~XKiBnSfAw&@SsS2=Cl4uT*_5`|WEe>L`bNT}{}&KYCZ z>vgx=9S(=%@p!phZnql|S(Y^#jeOr1=@R|NCY#-+W)GU# zQDJ=886Vd$ec{0Lm1+9Y=N}&*d7g95KM$oZ8vxFEp6C1hUiAC@IF9uS5Rn4*dOcCs xb)M%M(XZAtjd(tvWmy_}{FY^@|6Tni^8<4;MFy)lo$UYs002ovPDHLkV1iu`{j~r9 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Circles/b_quarter.png b/original_examples/samples/Circles/b_quarter.png new file mode 100644 index 0000000000000000000000000000000000000000..5932768d9ddcbbf3da96e2d0259a57f9ded67844 GIT binary patch literal 509 zcmV!!GkEDb+olccX1&N0s`3NzcPLX&B zew5^pZ$fLGJP<_@$?bNV%jJ;ZL-A7?V@S^Db0ipoUrUVfcnlzwN+l0G20j=Jk}eskdI=ccfroLw-~0VO0N?lDpZSk~7_wI~53Ti^WB&~hL*}tqEV9|GM0xoj z{sD*~d$rr`I-L#xrPOOL_BS9UIie_<&1U6t8Gz?`&!%|>knX}+g)o3(oHk;{m`o{ns-}=iX zkEXSjUrKVn->=u}&1MsZ;o)$&-EP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/original_examples/samples/Circles/w.png b/original_examples/samples/Circles/w.png new file mode 100644 index 0000000000000000000000000000000000000000..4804c6cfb4b98def78e8f17c1b7a7a4e65769369 GIT binary patch literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={WI14-?iy0WWg+Q3`(%rg0KtWAU z7sn8f&bMa`85tNj4jUZU|2&atUx>qH&sUo(_c8-jfI-7yvEv_^ZM`&S>Vo*5u6{1- HoD!M0WbcEP)KlrfItKoCX0n*<{fBOF^Y5+q1I0|8f~Z{R~fL;zd? zVSEN?iMHebN6_8X6V%9JMzgcp9dERLkyUcN>aK4&Afg}$@Ne+mi~Ie~Ppzu~)O9Vc z*K51#S1y-}$nzWk5w)vkVNn#~a5w;HJq8x;_j^Q9q_y_m6OnHTR%xxHC=yDk^?D7! zIoH-7MvRx7Uld;m+Nl<#s*BMigi@#wub z#{9(2?WfaeFc>sZLkIyNNfJ)`uV-+h)_O9TG}?D~QE8f%Wy#n4qdbU+H&d2nnx>8L z16+#Z_Ck*~~<&FlBBndyC z&-tRCbvm86>$(7>l=-3w=y@LB?REfiF9QL$+bs;k2!cQ2=p-(N15 z0J1F0Yx{&+tyaG813(l9UG#d5${YIlvtyTdfN#gsy>$;oGX1!itE|=$!_Z|OsoFbIFMK3D0$i;r9#r|l; zwu-`=UE%E-MPE1o=JUDw*qmn(YOz=VDE`tPkH@;M=Q}_$#-xlMt<`EuseFe!0>*L7iXPwp0NMPg7(;u*fdBvi07*qoM6N<$ EfoXG0|1!w zkdEV+1#C7OL#_V;7K;TKHLz_P0E7^x0JGWbd_GGl4N1uLdc9mO!Pt}}08Azm0MJ^S z0*po@0FY9e00013mNlQxiAX6$L6?PyN~v%-T&vZTQo(!hf~M2y{eDkGTI+xfctoeu zDH@Gdt5t&%sZ?sa-3BgUF~hPf*LAPgYrS4KBJtm2JRTE~@B2X+d;s{X3x&e*c%w6pNMX^+b<0s0E7@i2t*tX zhree$mS9FG6dDW$MC5ti+nIkkC?N#zRkzzEBH#Dli~YMWgb#3oCO|{#S9GGLLkg|>2BR0prD1P zi(`n!#N?E-Pm&Tq;D_yB>BFsBY$gd8*uoFA=(S5vSTKd9Hdc^((8m%R%#gTd3)&t;ucLK6V3QzqpA literal 0 HcmV?d00001 diff --git a/original_examples/samples/Circuit/component.png b/original_examples/samples/Circuit/component.png new file mode 100644 index 0000000000000000000000000000000000000000..fbb5fa1110d65a86139a45daf90b3d00e0049aeb GIT binary patch literal 103 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1SBVD?P>#3oCO|{#S9GGLLkg|>2BR0prE9u wi(`n!#AFjw(^LgM1HqMfAum@1v9Yl+O#jQUds>(E2cRMbPgg&ebxsLQ01UPmqyPW_ literal 0 HcmV?d00001 diff --git a/original_examples/samples/Circuit/connection.png b/original_examples/samples/Circuit/connection.png new file mode 100644 index 0000000000000000000000000000000000000000..3061705319b63c503c73f1845a46a99c8922ff46 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1SBVD?P>#3oCO|{#S9GGLLkg|>2BR0pkS1z zi(`n!#N?E-Pm&Tq;D_yB>BFsBY$gd8*uoFA=(S64STNIZ&8458pD*@QS5rH5Q^g|T zz*Hlrrnld}#3oCO|{#S9GGLLkg|>2BR0prD$k zi(`n!#N?E-Pm&b)3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/original_examples/samples/Circuit/dskew.png b/original_examples/samples/Circuit/dskew.png new file mode 100644 index 0000000000000000000000000000000000000000..f9a07f492cc909577d3e9b4a94e8bbcbe7eafc8c GIT binary patch literal 190 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1SBVD?P>#3oCO|{#S9GGLLkg|>2BR0pkRTg zi(`n!#NLU!1se=_oafiNA2wNYluJ@Udqdc=g$oxleA;_s$Cte)CMliX$8?}{4ufXE zd9lX!i+gJB=WKKgKA|-!G&WbWN>2A|>Evs-df!G{zi0bv`k`4bb>|j|x#gOvK30pD l?#sLU>R-C!@g>H;*s}VZ1Kw)x+Xl3o!PC{xWt~$(699YvNG<>X literal 0 HcmV?d00001 diff --git a/original_examples/samples/Circuit/skew.png b/original_examples/samples/Circuit/skew.png new file mode 100644 index 0000000000000000000000000000000000000000..260df54c83bf5fb81bdb6a4d7b0eb94a90b64627 GIT binary patch literal 180 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1SBVD?P>#3oCO|{#S9GGLLkg|>2BR0pkSJ( zi(`n!#Hr^u@-`?4xIJX=?7h5UnzjLh_71VjH*Q2Y=oLI_toM|QFUqqnW7u(?TfzNS zE6bE)r<4B*2Tgyb(Is4(RsBnHTNrQj>NZ=y_OI!`)~yY>`grq|Q&WYvZk>K*lj_&< aUksZn<$ft8TkZqe$l&Sf=d#Wzp$Py6{6We9 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Circuit/substrate.png b/original_examples/samples/Circuit/substrate.png new file mode 100644 index 0000000000000000000000000000000000000000..2c3aec02bfe32acfbb1a625a1c1aaa587ed2b3d0 GIT binary patch literal 103 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1SBVD?P>#3oCO|{#S9GGLLkg|>2BR0prE9u wi(`n!#N?E-Pm&b)3zopr04f9+y8r+H literal 0 HcmV?d00001 diff --git a/original_examples/samples/Circuit/t.png b/original_examples/samples/Circuit/t.png new file mode 100644 index 0000000000000000000000000000000000000000..084c3602bb8e0d2a19da7d468d09983ecc628fd1 GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1SBVD?P>#3oCO|{#S9GGLLkg|>2BR0prE;@ zi(`n!#N?E-Pm&b)3-nFUtWJWOCp9b c_YN0>d>ea+#HDFhfkrTRy85}Sb4q9e05}{azyJUM literal 0 HcmV?d00001 diff --git a/original_examples/samples/Circuit/track.png b/original_examples/samples/Circuit/track.png new file mode 100644 index 0000000000000000000000000000000000000000..01158cbf91a0d33c534541cb10412183d5f84bfc GIT binary patch literal 118 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1SBVD?P>#3oCO|{#S9GGLLkg|>2BR0prD4Q zi(`n!#N?E-Pm&Tq;D_yB>BFsBY$gd8*uoFA=(S7tXvv0hF|5>Nof5mCSQV&;!PC{x JWt~$(696erA8G&q literal 0 HcmV?d00001 diff --git a/original_examples/samples/Circuit/transition.png b/original_examples/samples/Circuit/transition.png new file mode 100644 index 0000000000000000000000000000000000000000..42ea71f4ffe39aa05383e64882e3aa89637dec15 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1SBVD?P>#3oCO|{#S9GGLLkg|>2BR0pkTJA zi(`n!#N?E-Pm&Tq;D_zs+kbw3mJD!AN>Ykp6lT8Iz?r9_Ct9GX_UF}vP-owxC8{z9 zmU@)GP6+6_ntq}wU}#3oCO|{#S9GGLLkg|>2BR0prD(l zi(`n!#N?E-Pm&Tq;D_yB>BFsBY$gd8*uoFA=(S5vSTLn^LD&7u`vsSaocy|_@O6W> pD=%ZSnT?m^!;fyh>=PD#3oCO|{#S9GGLLkg|>2BR0pkSb< zi(`n!#N?E-Pm&b)HXMlDzr6nNDyBR!gTe~DWM4f Dl^HW% literal 0 HcmV?d00001 diff --git a/original_examples/samples/Circuit/vias.png b/original_examples/samples/Circuit/vias.png new file mode 100644 index 0000000000000000000000000000000000000000..eb7a35eb26f11d861a780b4fdaad177863fbc7fd GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1SBVD?P>#3oCO|{#S9GGLLkg|>2BR0pkTJA zi(`n!#H*7w@-`Uou;>e#_#F1qjBI3#P)rR=nq`uyq2se*O+fL||2mP|4)4)rxKQ-; zj^UbiuF0HhZV4_~`IKu)kk6bTrX!uq{@qGP_B~k?D8rNfW1-gX;)@zZ`8T%y7H+xD fU$NrDiuo~Y50y4rwl9?dTFc<+>gTe~DWM4fGS@&T literal 0 HcmV?d00001 diff --git a/original_examples/samples/Circuit/wire.png b/original_examples/samples/Circuit/wire.png new file mode 100644 index 0000000000000000000000000000000000000000..958d10c0b9ab92abee6b5cdde7794dc97d64b9c8 GIT binary patch literal 116 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1SBVD?P>#3oCO|{#S9GGLLkg|>2BR0prD$k zi(`n!#N?E-Pm&b)31|%O$WD@{VjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCf`#@Q5sCVBk9f!i-b3`J{n@rk*a2AsWHSfB0E=SQsJ%m6esJbaOhS9T43+ zHL#IOx#7cP>jYPy0J}Jcbk`%l`A!{Yl#pPEdM5vioo`zf&;SNcS3j3^P6!lvI6;>1s;*b3=DinK$vl=HlH+5FvHWuF+?LcIVB>~z*g7(_LqmYWb|3Hc2M;R6bjlKT8%FeSo>69;u%7V=kHj(d15yX(IUe4@ z5W#$+_=SXcgSBVnWPO>(%qrEh_H;BCbTabrFkHwqc`EaScRJ8c22WQ%mvv4FO#npC BKDqz^ literal 0 HcmV?d00001 diff --git a/original_examples/samples/Dungeon.png b/original_examples/samples/Dungeon.png new file mode 100644 index 0000000000000000000000000000000000000000..64ce90dfa9bfdc59ebdc327dfb5e5bf0f04a89fd GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^f=GV8wJWt2k!5Fbg{BE{?ML!fr%%qg`?e!eowM6RV%vYDc_X2ce3QgJ@1!x{=eSo xcf9DBhIX6Zwj;MZZ>4;D*mLknOH)##`1Gg7f96@#SpjWh@O1TaS?83{1OWCUNJRhu literal 0 HcmV?d00001 diff --git a/original_examples/samples/Fabric.png b/original_examples/samples/Fabric.png new file mode 100644 index 0000000000000000000000000000000000000000..538259dd60891f70a7017afff883f80e6fda7030 GIT binary patch literal 120 zcmeAS@N?(olHy`uVBq!ia0vp^tRT$61SFYwH*Nw_oCO|{#S9GGLLkg|>2BR0prDqg zi(?4K%-mCod<+IWhaGnRuP-**;H7MAm2jKs)lmiqp?z^^cwAFuL%Yr#Vu^Wiqk%J`BhzWBjIaUQ)@~7#fERuz;_VqjzkQ$n zWyuns^IG-ohiYF`y)uq<)Kc~=*voM8!q?AEH+2BR0pkTD8 zi(`n!#JQ6K`3@*>ILDuPms?f5f0_@s)f@Is5iU(81p(0)!Y5~M4QVfR3=-RXQutwv z(ies==C=>u{jVIga_yI;Hx54P4QwlWa5-?Rb)Gn>~}-L0x$6>fB%o^n-n!CdRlr?xNMet6;(%kAryX_b6D`u`{6 Y=S5m7=gVfC16s%6>FVdQ&MBb@0EhHKzyJUM literal 0 HcmV?d00001 diff --git a/original_examples/samples/Knots/corner.png b/original_examples/samples/Knots/corner.png new file mode 100644 index 0000000000000000000000000000000000000000..bcc6ef7d65562ffc3386651e5b509c580cfa33e2 GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V6Od#IhtfB(JbKN%AZ1UMz8 zn*Dk(`Q9%dv3?U_*EV5>o`U+*euX;M_Z&KK;6i2W^TKm=CH0$66=`P`85kIBsC(GP b&BQS8qVke2egSiVRx)_H`njxgN@xNARO>+B literal 0 HcmV?d00001 diff --git a/original_examples/samples/Knots/data.xml b/original_examples/samples/Knots/data.xml new file mode 100644 index 0000000..9cd54d5 --- /dev/null +++ b/original_examples/samples/Knots/data.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/original_examples/samples/Knots/empty.png b/original_examples/samples/Knots/empty.png new file mode 100644 index 0000000000000000000000000000000000000000..ccae147a479f665c44ab2237c7a0c61eb0368f44 GIT binary patch literal 99 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V6Od#IhU%~7Pz!^n LtDnm{r-UW|8#f{H literal 0 HcmV?d00001 diff --git a/original_examples/samples/Knots/t.png b/original_examples/samples/Knots/t.png new file mode 100644 index 0000000000000000000000000000000000000000..cdaba5a8392b6d6637703c3df746a95154c6f676 GIT binary patch literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V6Od#Ihe!cIIa3$w1Q4b pX@R3y$Nt>h+>1S}9l{%=8T=E3YtqtO+JWXVc)I$ztaD0e0ssuiE-L^4 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Lake.png b/original_examples/samples/Lake.png new file mode 100644 index 0000000000000000000000000000000000000000..56c9ceba610a2ddb7e5362ab68a9414594f69bf2 GIT binary patch literal 326 zcmeAS@N?(olHy`uVBq!ia0vp^B0wz6!3HEJ^yqE{QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0XBj({-ZRBb+Kpx|v!7sn6_|Fu&bg_;$3TrUQf+;;6h7+Phq z{*d9W7uTXA_W2qdVM#n@?%X-6rk=sNRbbncpm}^rJtA8tmc|&r-*0a8bbF47_&S+a zeJZiK+gWBjoECWCG1nHJ>A!2FPFL}~-YJ#ae%gz1;dzopr09fLHw*UYD literal 0 HcmV?d00001 diff --git a/original_examples/samples/Less Rooms.png b/original_examples/samples/Less Rooms.png new file mode 100644 index 0000000000000000000000000000000000000000..8f36e626245fb254c5fc47224548b06bb20817dd GIT binary patch literal 172 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9GGLLkg|>2BR0pkSP* zi(`n!#I=(G`5Fv3oGVYitAF|{QAOo&Wba>P?O08hmu^5JbJ7~yD-z3{SN)L6zHz;f!LLSF{D|%T Q0H93_p00i_>zopr0QgimUjP6A literal 0 HcmV?d00001 diff --git a/original_examples/samples/Link 2.png b/original_examples/samples/Link 2.png new file mode 100644 index 0000000000000000000000000000000000000000..8a8b337395c3ac42443b97cd93414a5e73b07142 GIT binary patch literal 198 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&k#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5Fxu0_F+?LcIVBdUjF}9KJpGKSg!lvI6;>1s;*b3=DinK$vl=HlH+5Fw4`$F+?Lc`42w}j|#&Ewx_=P0`$~&yxuN( zs)=a=+tOY;1uo_U;q<0g%2EgBvTXh}ca7GJV{9#Q_tOq!F?%qz_%6>naMQqH-{boX0?#v%n*= zn1O*?5QG`)Q{pEA1uHyV978nDCzllQ{y6WTmXNf7VZ#B5>T>OataD@EFZ^)v=$zR1 ziMQUosp8jbJmzbd)wr9_+?qKF?49dr5TI3!}W3F29 znAaeJW3jf=GhrTsnno9c10Q}$F5jHEOzHBC8wLj~5+s=!R(y26_%Xdy3+M(0Pgg&e IbxsLQ0F|*!>i_@% literal 0 HcmV?d00001 diff --git a/original_examples/samples/Maze.png b/original_examples/samples/Maze.png new file mode 100644 index 0000000000000000000000000000000000000000..6cfd1b7d834bfecdfeccc03ed6444c0ac1e3d764 GIT binary patch literal 200 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9GGLLkg|>2BR0pkS4! zi(`n!#M%kod<=>l&TAk33r`c9wai&ijLm+_dL`rOA`IX5FcnlWc(eP>pP4f)RK)PB zW%fr-^+Hb9rsgW4yyz3N7pgqGT=933)T%IxzuKPfFYJ1GQe<7g-L>tHJ)>{0y?T7> uwzw$|!!nxwEiA4(5Ssq&mc++WhKkn sOrHpjC}H2i_eU9j>C9tazqwdH^ZeQ$Y)9q!flg!aboFyt=akR{0M7zhRR910 literal 0 HcmV?d00001 diff --git a/original_examples/samples/More Flowers.png b/original_examples/samples/More Flowers.png new file mode 100644 index 0000000000000000000000000000000000000000..bc781e48137c8b79fda372289e3ebaa19e24b955 GIT binary patch literal 318 zcmV-E0m1%>P)LlQ9m$FbqYVh^a%*!U<5>xB(~N5*&lmv{Nfi!`z_* z3k;D`_y2Ds)J*Aj^5Sp1X?)GLdu5iorj`IWu#n!Vcmz>c^*OaJVksjvq*E+l(Hyt^e4kanMpkR=v zi(`n!#NJ7sd<+I0On?6`f4OpH;mk(|O!lvI6;>1s;*bKn+Jgm~pB$pEOV~!qdeu#KQmSgg`C^MGlwa@9NXbkC&-BJMFJl zIM%G`%kUyvH$+tI$-=IVBML`Po!r=eUQ%Su)H4$W-Uu|wB+Kg;A1Pn+>HUj?f3HnW l-v6w4*{bA&*NXW*Fx+Sj`Z~${eIC#b22WQ%mvv4FO#taHLc#z5 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Office 2.png b/original_examples/samples/Office 2.png new file mode 100644 index 0000000000000000000000000000000000000000..f3e23cda4b6dfb345f11645ba928bcdf9eaf919a GIT binary patch literal 332 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv>!3HFi<}R-XQjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0XBj({-ZRBb+Kpx{GK7sn6_|Fx4Ed7BM*SZ2Sw_*eaflR{~) z$^07!ZT>L@`FCxQeQqc(*W2~=-=1H=x?AO6FExw$AU^L~&6?L)7v0vR{!R!#o-#2t zQfHU{vg@6TUK~7Cv-pyzQ&nn{obK7!1x7zFixxHU*)UtiC?>iiqvXSSi@llzp z9>Ob3o8BxF$y$H)sayTA&N;z`_9aJmU*=BOac*9!kD+O#Na2<4WfF^DIqZG0DZ*yP c{FPt1d%IsPU8wfY8t7RDPgg&ebxsLQ08{0Nm;e9( literal 0 HcmV?d00001 diff --git a/original_examples/samples/Office.png b/original_examples/samples/Office.png new file mode 100644 index 0000000000000000000000000000000000000000..a4912f28fd57271aaa5fdfdbd647204a992fb6d8 GIT binary patch literal 171 zcmeAS@N?(olHy`uVBq!ia0vp^{2oCO|{#S9GGLLkg|>2BR0pkS=0 zi(`n!#HkYl`3@-XIGx_~JAP*E3=1_`w|`5P*ll^`vO;T;CgYg{rF(9>3N^@83+=r= z*LHi>(=di|sYzw8Gm5q|tIPfKnq>WEr+x5Iu8{m+{8#SV{oPaUk(pl25IMnyt$X?d Q6`(~7p00i_>zopr0E_rK!TGqMI@*IbwU;K1SHrGA+L zzMP16v`wcO2adZi5;$Y)ym(w~Z$Dpp>2e0DXftieOppe=(|gheV3T~*Pavi#%zPgy zcbTD}nF*r3Yh$mxQ^H_r{xC7)u>R#zMR<2Tp|{0nESTrFb3=S9Zq$=jRlPmpbdNL@ zL5!5DPQ)tK$^D3i3v-hDEsX^Wqle^zg#lKD^1_Hj zdR;_4S-`kQFsFY@m|#W&E+5%?vRZM>7LszBP7*YL3ai*37M=K=u@SOx*!lvI6;>1s;*bKn+Jgm~pB$pEOV~!PCVt#KJ%M4?hb}3d0&HNlD3tI&T=3ur5Eg z-AF4yj=A~6Wa|RE4&Fw}1mB_-MrLM)z=zhm(*Lae477{E)78&qol`;+0HTLGP5=M^ literal 0 HcmV?d00001 diff --git a/original_examples/samples/Red Dot.png b/original_examples/samples/Red Dot.png new file mode 100644 index 0000000000000000000000000000000000000000..44e5afba106eb84255b8a8446f5d79e44fbae049 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{VjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCf`#@Q5sCVBk9h!i=ICUJXD&8&4O<5RKsE8tuiO<~Is3XdYsB_~a9?HQ|F_ zm}uWb#u&j}EJpH2Rbm=UT%G#!og)Pr4yhk2cWDu3W@cF0@0a_b;)Es890pHUKbLh* G2~7ZhCM_-i literal 0 HcmV?d00001 diff --git a/original_examples/samples/Red Maze.png b/original_examples/samples/Red Maze.png new file mode 100644 index 0000000000000000000000000000000000000000..f716db2532191a60ce7a32e1c9c1011c8d90b5c8 GIT binary patch literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFm1SHiab7}%9&H|6fVg?3oArNM~bhqvgP*B>_ w#W93qX7Zo^|LvJ&6pCjoa5^F5#s&fm;+xqS+~k)o1S(_jboFyt=akR{0RFcZC;$Ke literal 0 HcmV?d00001 diff --git a/original_examples/samples/Rooms.png b/original_examples/samples/Rooms.png new file mode 100644 index 0000000000000000000000000000000000000000..4210deb1f6e15dc462fdd7e7c874737e38552040 GIT binary patch literal 181 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9GGLLkg|>2BR0pkTVE zi(`n!#JPcvdzDHJ@IZsD(?&( z#Y_X{2J1PKREp1beUBAu-(8dSe`Jepr6HBW!pWVI9R aC*vHxTZ;KfD=!6F$>8bg=d#Wzp$P!w;yrNy literal 0 HcmV?d00001 diff --git a/original_examples/samples/Rooms/bend.png b/original_examples/samples/Rooms/bend.png new file mode 100644 index 0000000000000000000000000000000000000000..fd27d078adaaf6c31ffc3294ea43f32af232ef13 GIT binary patch literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1SD^IDZKzvoCO|{#S9GGLLkg|>2BR0prC}O si(?4K%w&t29|p`|Ak55TaOfyQ&=i(whrVw$1*&22boFyt=akR{0NJw_CIA2c literal 0 HcmV?d00001 diff --git a/original_examples/samples/Rooms/corner.png b/original_examples/samples/Rooms/corner.png new file mode 100644 index 0000000000000000000000000000000000000000..5d9bf27ca1cc98a3b6f2295599d8497ac24e5718 GIT binary patch literal 99 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1SD^IDZKzvoCO|{#S9GGLLkg|>2BR0prELy oi(?4K%;W?xu&DWAz%0hVV3fk-Wo8h#0;qt&)78&qol`;+0HF63uK)l5 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Rooms/corridor.png b/original_examples/samples/Rooms/corridor.png new file mode 100644 index 0000000000000000000000000000000000000000..2fd942f90e7565cfd9fbca20e2aee35f3e9ad562 GIT binary patch literal 101 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1SD^IDZKzvoCO|{#S9GGLLkg|>2BR0prE*? ui(?4K%;bcG1dEy<2F%RN!puAh5e$~qOnxjYzDEF+FnGH9xvX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/original_examples/samples/Rooms/door.png b/original_examples/samples/Rooms/door.png new file mode 100644 index 0000000000000000000000000000000000000000..6cd050017c1db98662be7697f02483a5840ea12e GIT binary patch literal 97 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1SD^IDZKzvoCO|{#S9GGLLkg|>2BR0prEj) qi(?4K%w(II9|p`a4i-KIb__|AS*Cr-*;xXVX7F_Nb6Mw<&;$UBh!(^E literal 0 HcmV?d00001 diff --git a/original_examples/samples/Rooms/empty.png b/original_examples/samples/Rooms/empty.png new file mode 100644 index 0000000000000000000000000000000000000000..c2eea5ad3ae5bbc92be3f96f542f4280e605a99e GIT binary patch literal 101 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1SD^IDZKzvoCO|{#S9GGLLkg|>2BR0prE*? qi(?4K%w(II9|p`|Ak5685W(P3!sP$!mcT!t5(ZCKKbLh*2~7a0suivP literal 0 HcmV?d00001 diff --git a/original_examples/samples/Rooms/side.png b/original_examples/samples/Rooms/side.png new file mode 100644 index 0000000000000000000000000000000000000000..2fe2883e7b3bf64cadbcb55e521d4670ebcd819d GIT binary patch literal 95 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1SD^IDZKzvoCO|{#S9GGLLkg|>2BR0prD|q oi(?4K%;bavEIsY~@@*R!gbJ9v_pSdu2Pnzl>FVdQ&MBb@0BM#MqW}N^ literal 0 HcmV?d00001 diff --git a/original_examples/samples/Rooms/t.png b/original_examples/samples/Rooms/t.png new file mode 100644 index 0000000000000000000000000000000000000000..47b93c775ec185d703f03a1b729f49f8702faba9 GIT binary patch literal 98 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1SD^IDZKzvoCO|{#S9GGLLkg|>2BR0prDAS ri(?4K%;bay#$$)u`43z22=FnO9Auf&G4)V7P@cil)z4*}Q$iB}tDqM# literal 0 HcmV?d00001 diff --git a/original_examples/samples/Rooms/turn.png b/original_examples/samples/Rooms/turn.png new file mode 100644 index 0000000000000000000000000000000000000000..9db18d7086fbcce6b0c4e8c3b48badadefcb5032 GIT binary patch literal 100 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1SD^IDZKzvoCO|{#S9GGLLkg|>2BR0prDwi ti(?4K%;bcG1dEy<2F%RN%5z#77@}vfOgS*gcO6g#gQu&X%Q~loCIHKz7hM1V literal 0 HcmV?d00001 diff --git a/original_examples/samples/Rooms/wall.png b/original_examples/samples/Rooms/wall.png new file mode 100644 index 0000000000000000000000000000000000000000..90aefbe165bda984cfbf0252714fed7357cccd83 GIT binary patch literal 89 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1SD^IDZKzvoCO|{#S9GGLLkg|>2BR0pdh!W ii(?4K%;bav>pGwn;=mR9JZ)qqkZ3dA?-_cl+h zJ9FxL=qX6CpO850)$E?ZL8Kb3J`SQWi_m{WCB;$Y#J4y?byZG0gTv}|aJE)PmAFLXjpRG>5- zJe$XQ9_vHX!@bNK{RJsz5Tb)yo4!z;XvTIWAIxLQ6GfmKGdt*=AA%le4xRP=&{z*N zcVmNtd!vKqZd|*1F;@R#I1jm7F%F&9IB3+6rU~`xw5FI8U z>{I?g&#JpDG~r8+bP+Dxb~y#V!EaoRq1q4}}-Q^7$10000!lvI6;>1s;*b3=DjSL74G){)!Z!pp2)BV~9j}@{fLIfk_DmSX?|6Hg`^TV7#F! aA;ECDGk#&xGfr#R24i5WYYCN`|u zRvRFe$8hCz!)1mThMNf+7#*aZlyq8}BYDhb*AFsy=mzTj z2wT?Qn8=VWp}?HNYjEIdso)!?9gH_b9x@v+Yw)@7FgvI%POf2C&F$dVoaoe`q5q&* z^jd_%u{4Q>-3+#Mova_uuw3qWW0S;?e7@bOX{TU{#;(^1Ng~UcC!J=_VMt++aOPEJ dH2%ZRaN%|h^Ws}>wm|nYc)I$ztaD0e0s!U0TIB!$ literal 0 HcmV?d00001 diff --git a/original_examples/samples/Simple Knot.png b/original_examples/samples/Simple Knot.png new file mode 100644 index 0000000000000000000000000000000000000000..0e805cda16286b310fa1a8be8ba7dfff87094baa GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1SHkYJtzcHoCO|{#XvD35N5n|x9$&6(9P4u zF+^f&>jXzG1_ch5=(qpvue}v;>0G&e>QPCSlY!@WBoD}X9y@mLUhYak&%88Li&pg>pB}Vg!QYomyhlZ479A*i1T>Ms)78&qol`;+0NQdhE&u=k literal 0 HcmV?d00001 diff --git a/original_examples/samples/Simple Maze.png b/original_examples/samples/Simple Maze.png new file mode 100644 index 0000000000000000000000000000000000000000..c6c9bd4ebc5b311b88ef7ac561b68ffbf04d5481 GIT binary patch literal 99 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFm1SHiab7}%9&H|6fVg?3oArNM~bhqvgP*Bv< s#W93qX7Zo^|LvJ&6pCjAv`k24i1z3H(Ow@g3#fp>)78&qol`;+0G@Ui;s5{u literal 0 HcmV?d00001 diff --git a/original_examples/samples/Simple Wall.png b/original_examples/samples/Simple Wall.png new file mode 100644 index 0000000000000000000000000000000000000000..9369ff6ca81e0eaa30c1a0b21a53d309613d3a19 GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^f*{Pn1SGfcUswyII14-?iy0WWg+Q3`(%rg0KtUT% z7sn8diOGNd|F>t>N=QjLBH|*JerU>KP6rF->5~nXo+!MXaLt)7AtfO}!Dz>W1cP?Q hzn7(*I>ag&8Il(&^4b-eWCG1$@O1TaS?83{1ORBZC@ug1 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Skew 1.png b/original_examples/samples/Skew 1.png new file mode 100644 index 0000000000000000000000000000000000000000..65f27eafd92eb8c6f9d5ab616d9b3825663227e0 GIT binary patch literal 253 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S1|*9D%+3HQ#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5aFVBsV~BOM-;eG&+QnrQm{KOp z=u@UFRhT)ei$f-L6^Bly)`m$wkxPV(1s7z_(`$b7Cc=1@n-Wu|d2)d&(@LH@9&Af} u80YKWXL+r+HdFo<^J|B5DfY`UzcF1*w-u9k#S3&Q1B0ilpUXO@geCxS2342< literal 0 HcmV?d00001 diff --git a/original_examples/samples/Skew 2.png b/original_examples/samples/Skew 2.png new file mode 100644 index 0000000000000000000000000000000000000000..8c60b39956770543efe5c9e542f5bb6c98dbe784 GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv_!3HFka9+I#q!^2X+?^QKos)S9a~60+7BevL9RXp+soH$fK*1TFE{-7<{%a>j^ED{&uyB9hZ@fvX?fAEa z7MvfO-`rU0>EdOp=%qPHNNG+@eZ8X2;Sf2+Nc~Mq*7dZSF4Ww-ETR0BnXVvn^s>pW zE*#r0N2CM_CQo?V;jpUd!{dxa%T5%(Uw`1^l^%}0LWgI+<(i)Rj$`5ybNz2cO^P9s zA6kmLm!|cH&b&L*=z!BL{}{;^hp%l>l-!^quEai%)lRqf#=HqYH!^s-`njxgN@xNA DPm^7i literal 0 HcmV?d00001 diff --git a/original_examples/samples/Skyline 2.png b/original_examples/samples/Skyline 2.png new file mode 100644 index 0000000000000000000000000000000000000000..a7cd1e5601b52297ed51fd58109e5e28372f0824 GIT binary patch literal 6424 zcmV+z8RzDSP)004&$004{<0091~004v4004#&008y@0028f000$`8$yyL000** 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 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Smile City.png b/original_examples/samples/Smile City.png new file mode 100644 index 0000000000000000000000000000000000000000..8681f9f1889c0b02192aac31b36b989fdc02c7d7 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sDEfH31!Z9ZwBpoOQ4V~9p@a!NwN5B?(-j1i0i4iy;<6DLk= zXI!IZQrIFFxiP@ESEP5M|kO@&E&a`)1}SqwcQw~}U6HxA yJGAm#U(^}9^`DgMf9~W^*(~m+FmtO(Q|*TzhU}IB0_;Gm89ZJ6T-G@yGywqHpGwdG literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/cliff 0.png b/original_examples/samples/Summer/cliff 0.png new file mode 100644 index 0000000000000000000000000000000000000000..a921d79b78a9c1009bedc49619b311a481b92210 GIT binary patch literal 4906 zcmV+_6V>dAP))oBZ_=fiz-V1zU_n&d_l3L8GH08msupHifm)VS7kMWoXzusqbQPHgb>Rmtrl^NQaBE$ zr{#FeixY6;Gt{HB!T4g~%tHtIfLW(OEx3{S(`hEI+#^+3@ z?CovWC7vbI7;ErH2uZu6R`a6SB#yBpN>W!9f+)gw%*nCnbnrb!XCm-%Tt*l4+LSqG zXL4&xEEgthU&pDrF|~PNQ-C+(dzUW zdqWj?$ms|#lf|ftXB1!1J#GvQ;Ni_x23DC^_F$^*ocL-(Uj9?4B=pCf5o_u z|2@n|O5I-ADsY(pxmF932D1mechAc<^yvk6`yL zG5Lg0o9vv;mQo`={M$HLQG81OsQ&Vz7X6TE!kcaDsHjECg`g9%*%F<~BCA?!T+CUe zjB^^AGY8A(57xbSrblJ@aAp3%w|yn8fAQZV16b??q_!v*W~mW^jz^JWE2P9oY8SVK zo^#t$pQKewF-|cRw+vku*Tb@qmoc{u-LM`dTo^FSBbKMe7u9OPXHPkq@-$^xGdGx= zYEC1_?!Mu6Fiy>?GoL@{6&yv|`npVsuhhJoMXm|Cgg=YR9S_tf2k{;A>gtmw4;Rv31>o$a0B z{=w!qUfa068NRk@%Yu!*{rXpSdM+V^Flcc1mEC?vw+Vz1M@jqyfW0*zUAj?M9Mhv+2C3c>01O z%jMSg&=U9(X<22FyRH)@g;Mh9ltlCR$w`(|l;kDHCuvcX-A?n-&Y_%v;qbj!)Ci9EqQry_QiuokDiuUfvu>(lG1U5!FrGXgEUDz-;I*OlHy`Q zQt|ZgTwa`w4>i7v(Rw*wrb!z3c2QP0HrQbSS-v0 z+UEA&%lDr=_;fa3DP`G;(Uh|hS4E`PM%i{h(3z z3XlT1$^g1;@AUbzkN@f~X0z4a-d0uBwvvs2yd*EmMl;yk!E>+M{3@Vj#OcWh2s|u- zG1vVYC#<4!I3OzlHr4=^5Jz!YWO)hD>-uNUpMCVRpI%&C?(c6~QfiIsk`>4(qYbuW zKm7EIpZ)Z+C{B0xZg{S{TxlUFE1o_#c~;zi<)-V9<_G~0`V<9Eo)u-ujUla&+5l9V z<0)qsblaZMXoID$^%cmHcv;W}+g6`{_V|Mj9;Ru&b8}ZIwTg|DlofK&VyG}$8)IA# zOG?-GYhC9B-8REMamv~Gq|6IrC@YKskP_RbuCWwCP}LZXka#v0oK2~!>gE>8;_w(? zzs<(>R;RbV)n=%!N^dNQQkJx2RaIq4ufuu|d1C|LVSE{vW#xOeWy#fIS(eqHFZ*53 zb+8r9W>{;}Y7)5D0bM~U{w|D0TDXebuvk`}gJqHC0IepLrDl_h;Q-HOG+x!(grTi0 zD^Jt1tk!yB&<_G1DJ`Vn>2t=HiR;+yc4IML=vpgfWqA?B*cQr?QqXP+*QF@=tq2t- z7sM%Ax7w#Yv0+ZD{rS*A+1&*gwXYG#`w2FgJYu& z4&3+XwQ*d(EGoEm*J&e#kU~~f?K*a|ffSS#(oxhJTj4qCYH2EErD^8aqSfSTZ2(fp zz*kCLuhjoPu69zKkma--1|33QjZcn*6jESW*a~F{+g8#NN?BQ6Dn+Y_5J+j^I;;}L z)2i0maUDy_`7${?Hmew0k!6e~OKo(2tsVH3^=}Udums~7^B7~OD&n*{e)g;^Yo(}b zqLk^}R8=j6kU~yptCKV01lQ(Ti-jP~m`;~~ZQIJa5@Dpc9wjNHZQI&#RpQ?YAut9Z zuoX%X`l{7w*|ud2mW7bS3Cm?{Ny~9;DMYO?8e1VPi80uUvZN?=S(cV1;@AML%hgz| zqH8zx|3lBOD|odS|8AQLfhEXFq6DR6o~D+RQeN{{*JMRi)s^GgilLXzRT4EvN7FV3n#UoKb0G9vJh z7Pdl2q{MNE6P7tGkDVcoViJ*ScGhrhq7+BsIT({Q8h#XIb&ZrPA^_j5gTTx4comUk zgg(}{?}n~zTt_b>;uKwLN7Y)_LZB>cn?X-?TC%G2y?a~J%lXA6%?3rzDnVID$!bNE zv8eC`-4<1aXQ68_)S9B8)+{1ChuixDV~po$+t$m7IH9g<*QvFxYmFuFT&(ZEv#sme z^Bt{=Bqho4+{&>)_ zv%4*OEps|zl#&CWHJ+l^k%RTVu4~t^lq{o!MTGBGjw1wwKAwl1Ue5c2uCnCrPP5nM z(F$Yebz8QL?(OAE(kYonzuM)O|3Qxv78ETve1 zZPRQ9;Ucbe4Xm%Vm&^G1@nW$e&F~!34BzGTb(E49W9Ei?P4;%wGO41NQfrM#;#5lR zuhDAaxhx~jCVZB0Yrg6adUaK!uoVR;MY9?D-U5)8v~D#qI**ggvZS)=b;V@L#=6sJ z`ejkYN!IJOFK4SSk0>i#o3f&+SnKlgK}%ZJ&mI;N!8i73u6w6dx$>!1A!Ri>k1sEI z>ubHYzj^<1JU%+rO`jrR&@jT3%T=nB^c?z@9*x;px5Ln{sya<`xm@wrzeuNZlV{~W z`O`nUf2UnmOsC7WwO*qcc&>B&V)V)9#5uQa;QK@=y$)+VQI?gi>+iqqASpVGUQa)H z1M43$`yt0~W#c`f26tXN*t)s*i_faE;_a{Z|Kz*P`I5i*dAwMevaJ5`pZ?jsms;Ae zTqf(oHP3gIQq~{8)46>!D9iNT{k_qPL*I9gUW^+d-EMPtZ}&TY?+=uyrsIoYpLgE5 z*YBt_iQap6zuRm7$Nw^pqjG0E@J!MBzW-#i5^ER-w@=n(zAojK+TGcF`pYl=(}U$d z`oUfh`u%<{^s8IDUY=!lUcPyGde~@$M@JX!rff9BgO~T;|NY;S<0|$x8t?z$JE<&#=-5^?sZGSi69|V@|u5WGjIzkH4G@UQvBx5|9E@n$%5e7tY>JB(;R%U0V)-?{jp-?k=-A8=D-RS92%7`Ca={^XR9GY_VH? zlvJ&rb^GrA$@3S{BKqdLUz=Y}M&nhU=dNvzo;+5aH>vy4Up{@(y@U4(|MV~a{KjTI z*k^oVJ<>-(gXOl^dD~mF_1Q@gD=xj z3|pTbX1!aOHS(@0`z(FDn>42fe_OYOR3 z8Bv7q)9LX1Irr{`=jVmz@$4DB9$PomBCqlur%mxxE}WP1xFyR@6*;&!u-d;zSyI>d zK9flvMT8+iK$2V^Q|cP6NmKfL8VxH+jg%~x^!uEiUdw8)N0uQ3S%xv>IZ_hGtgVqG zC{;`*Y-})}bLS39F`b$$XRyifyz*~R+%U6kF1BdAj|@Y!rrEr{W8Aob5L{kfKeLRw z=Hvy c4iC%!4Tz-(C%(8=K>z>%07*qoM6N<$f@8+qQ~&?~ literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/cliff 1.png b/original_examples/samples/Summer/cliff 1.png new file mode 100644 index 0000000000000000000000000000000000000000..6f367315df6e942e8fd4bcfb45e753a54eea5041 GIT binary patch literal 5113 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 b&$9U6V1ro7U~eAh00000NkvXXu0mjfb>I}~ literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/cliff 2.png b/original_examples/samples/Summer/cliff 2.png new file mode 100644 index 0000000000000000000000000000000000000000..c3b96f220bb787eba7ca40a998c1d541f464b79e GIT binary patch literal 4806 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 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/cliff 3.png b/original_examples/samples/Summer/cliff 3.png new file mode 100644 index 0000000000000000000000000000000000000000..4c45cfeb94ef011710c088de15111d3754cb5ca7 GIT binary patch literal 5475 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 DFY8Dk literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/cliffcorner 1.png b/original_examples/samples/Summer/cliffcorner 1.png new file mode 100644 index 0000000000000000000000000000000000000000..d94efeddce56490fa618300ce7c579c4635aef3a GIT binary patch literal 4608 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 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/cliffcorner 3.png b/original_examples/samples/Summer/cliffcorner 3.png new file mode 100644 index 0000000000000000000000000000000000000000..14e3035e90ed8e53dda6efc5243aa0a4249aba03 GIT binary patch literal 4975 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 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/cliffturn 0.png b/original_examples/samples/Summer/cliffturn 0.png new file mode 100644 index 0000000000000000000000000000000000000000..1dadb94f89445f55f5b8772c326d5e72e8b94f22 GIT binary patch literal 5251 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 JPDHLkV1hPrVT%9& literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/cliffturn 1.png b/original_examples/samples/Summer/cliffturn 1.png new file mode 100644 index 0000000000000000000000000000000000000000..f9e9ad2645aea8eeae1eff36f8d5650af1245d06 GIT binary patch literal 5167 zcmV+~6wvF5P)cxqpM9_|hT)@*h5-X64;CZ{CS}v&HZ#rco|*3H?y9b? zJ@<&n*yAleR7v!I2q5ssi}$bJ_x?xj{wJKD!}qYaOFnt5{e5)*4|fakVvbHgzx(SO zd$(@nNgRc-QqpVnA3i*8xkb0*9iLD357lHPs}gNT54!MOEFzdDdL2#(7-a^h8bnF4 z%4E0WURtVT@ghZc7123bz@}2EA_!dznGDE zgwG-z&ehRe&0|H0W>kSP&L~mR^{l`7+u48o!K1J2*hOCa^$#xy$-`cL-_D~j^j%akeog)eT3s(OBq7)H6hwZ3tE z-8Okq)EASgD9fGe1FdzMRV|ODmF_gLv2HDv;?)F23XAGYXr*C0)UizAMgC$ zpZ=L?l35j=@6N}i4gvruOR$d8?^-+A2jStN^rslQSV=T&@{MkFMi_>ssb4=kmqyTSa+B+q`^Rg&hHKNZ5UWJ)hk9J= zoen$~7gM+lWrc$bs|b)N3M|9whd)03
+    //! void %rapidxml::%parse_error_handler(const char *what, void *where)
+    //! {
+    //!     std::cout << "Parse error: " << what << "\n";
+    //!     std::abort();
+    //! }
+    //! 
+ //! \param what Human readable description of the error. + //! \param where Pointer to character data where error was detected. + void parse_error_handler(const char *what, void *where); +} + +#else + +#include // For std::runtime_error + +#define RAPIDXML_PARSE_ERROR(what, where) {if (*where == Ch(0)) throw eof_error(what, where); else throw parse_error(what, where);} (void)0 +#define RAPIDXML_EOF_ERROR(what, where) throw eof_error(what, where) + +namespace rapidxml +{ + + //! Parse error exception. + //! This exception is thrown by the parser when an error occurs. + //! Use what() function to get human-readable error message. + //! Use where() function to get a pointer to position within source text where error was detected. + //!

+ //! If throwing exceptions by the parser is undesirable, + //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. + //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. + //! This function must be defined by the user. + //!

+ //! This class derives from std::exception class. + class parse_error: public std::runtime_error + { + + public: + + //! Constructs parse error + parse_error(const char *what, void *where) + : std::runtime_error(what) + , m_where(where) + { + } + + //! Gets pointer to character data where error happened. + //! Ch should be the same as char type of xml_document that produced the error. + //! \return Pointer to location within the parsed string where error occured. + template + Ch *where() const + { + return reinterpret_cast(m_where); + } + + private: + void *m_where; + }; + + class eof_error : public parse_error { + public: + eof_error(const char * what, void * where) : parse_error(what, where) {} + }; + + class validation_error : public std::runtime_error + { + public: + validation_error(const char * what) + : std::runtime_error(what) {} + }; +} + +#endif + +/////////////////////////////////////////////////////////////////////////// +// Pool sizes + +#ifndef RAPIDXML_STATIC_POOL_SIZE + // Size of static memory block of memory_pool. + // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // No dynamic memory allocations are performed by memory_pool until static memory is exhausted. + #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_DYNAMIC_POOL_SIZE + // Size of dynamic memory block of memory_pool. + // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool. + #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_ALIGNMENT + // Memory allocation alignment. + // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer. + // All memory allocations for nodes, attributes and strings will be aligned to this value. + // This must be a power of 2 and at least 1, otherwise memory_pool will not work. + #define RAPIDXML_ALIGNMENT sizeof(void *) +#endif + +namespace rapidxml +{ + // Forward declarations + template class xml_node; + template class xml_attribute; + template class xml_document; + + //! Enumeration listing all node types produced by the parser. + //! Use xml_node::type() function to query node type. + enum node_type + { + node_document, //!< A document node. Name and value are empty. + node_element, //!< An element node. Name contains element name. Value contains text of first data node. + node_data, //!< A data node. Name is empty. Value contains data text. + node_cdata, //!< A CDATA node. Name is empty. Value contains data text. + node_comment, //!< A comment node. Name is empty. Value contains comment text. + node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes. + node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text. + node_pi, //!< A PI node. Name contains target. Value contains instructions. + node_literal //!< Value is unencoded text (used for inserting pre-rendered XML). + }; + + /////////////////////////////////////////////////////////////////////// + // Parsing flags + + //! Parse flag instructing the parser to not create data nodes. + //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_data_nodes = 0x1; + + //! Parse flag instructing the parser to not use text of first data node as a value of parent element. + //! Can be combined with other flags by use of | operator. + //! Note that child data nodes of element node take precendence over its value when printing. + //! That is, if element has one or more child data nodes and a value, the value will be ignored. + //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements. + //!

+ //! See xml_document::parse() function. + const int parse_no_element_values = 0x2; + + //! Parse flag instructing the parser to not place zero terminators after strings in the source text. + //! By default zero terminators are placed, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_string_terminators = 0x4; + + //! Parse flag instructing the parser to not translate entities in the source text. + //! By default entities are translated, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_entity_translation = 0x8; + + //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. + //! By default, UTF-8 handling is enabled. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_utf8 = 0x10; + + //! Parse flag instructing the parser to create XML declaration node. + //! By default, declaration node is not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_declaration_node = 0x20; + + //! Parse flag instructing the parser to create comments nodes. + //! By default, comment nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_comment_nodes = 0x40; + + //! Parse flag instructing the parser to create DOCTYPE node. + //! By default, doctype node is not created. + //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_doctype_node = 0x80; + + //! Parse flag instructing the parser to create PI nodes. + //! By default, PI nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_pi_nodes = 0x100; + + //! Parse flag instructing the parser to validate closing tag names. + //! If not set, name inside closing tag is irrelevant to the parser. + //! By default, closing tags are not validated. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_validate_closing_tags = 0x200; + + //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. + //! By default, whitespace is not trimmed. + //! This flag does not cause the parser to modify source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_trim_whitespace = 0x400; + + //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. + //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. + //! By default, whitespace is not normalized. + //! If this flag is specified, source text will be modified. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_normalize_whitespace = 0x800; + + //! Parse flag to say "Parse only the initial element opening." + //! Useful for XMLstreams used in XMPP. + const int parse_open_only = 0x1000; + + //! Parse flag to say "Toss the children of the top node and parse off + //! one element. + //! Useful for parsing off XMPP top-level elements. + const int parse_parse_one = 0x2000; + + //! Parse flag to say "Validate XML namespaces fully." + //! This will generate additional errors, including unbound prefixes + //! and duplicate attributes (with different prefices) + const int parse_validate_xmlns = 0x4000; + + // Compound flags + + //! Parse flags which represent default behaviour of the parser. + //! This is always equal to 0, so that all other flags can be simply ored together. + //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values. + //! This also means that meaning of each flag is a negation of the default setting. + //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, + //! and using the flag will disable it. + //!

+ //! See xml_document::parse() function. + const int parse_default = 0; + + //! A combination of parse flags that forbids any modifications of the source text. + //! This also results in faster parsing. However, note that the following will occur: + //!
    + //!
  • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
  • + //!
  • entities will not be translated
  • + //!
  • whitespace will not be normalized
  • + //!
+ //! See xml_document::parse() function. + const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation; + + //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. + //!

+ //! See xml_document::parse() function. + const int parse_fastest = parse_non_destructive | parse_no_data_nodes; + + //! A combination of parse flags resulting in largest amount of data being extracted. + //! This usually results in slowest parsing. + //!

+ //! See xml_document::parse() function. + const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; + + /////////////////////////////////////////////////////////////////////// + // Internals + + //! \cond internal + namespace internal + { + + // Struct that contains lookup tables for the parser + // It must be a template to allow correct linking (because it has static data members, which are defined in a header file). + template + struct lookup_tables + { + static const unsigned char lookup_whitespace[256]; // Whitespace table + static const unsigned char lookup_node_name[256]; // Node name table + static const unsigned char lookup_element_name[256]; // Element name table + static const unsigned char lookup_text[256]; // Text table + static const unsigned char lookup_text_pure_no_ws[256]; // Text table + static const unsigned char lookup_text_pure_with_ws[256]; // Text table + static const unsigned char lookup_attribute_name[256]; // Attribute name table + static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes + static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes + static const unsigned char lookup_digits[256]; // Digits + static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters + }; + + // Find length of the string + template + inline std::size_t measure(const Ch *p) + { + const Ch *tmp = p; + while (*tmp) + ++tmp; + return tmp - p; + } + + // Compare strings for equality + template + inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive) + { + if (size1 != size2) + return false; + if (case_sensitive) + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (*p1 != *p2) + return false; + } + else + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (lookup_tables<0>::lookup_upcase[static_cast(*p1)] != lookup_tables<0>::lookup_upcase[static_cast(*p2)]) + return false; + } + return true; + } + } + //! \endcond + + /////////////////////////////////////////////////////////////////////// + // Memory pool + + //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. + //! In most cases, you will not need to use this class directly. + //! However, if you need to create nodes manually or modify names/values of nodes, + //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. + //! Not only is this faster than allocating them by using new operator, + //! but also their lifetime will be tied to the lifetime of document, + //! possibly simplyfing memory management. + //!

+ //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. + //! You can also call allocate_string() function to allocate strings. + //! Such strings can then be used as names or values of nodes without worrying about their lifetime. + //! Note that there is no free() function -- all allocations are freed at once when clear() function is called, + //! or when the pool is destroyed. + //!

+ //! It is also possible to create a standalone memory_pool, and use it + //! to allocate nodes, whose lifetime will not be tied to any document. + //!

+ //! Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. + //! Until static memory is exhausted, no dynamic memory allocations are done. + //! When static memory is exhausted, pool allocates additional blocks of memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, + //! by using global new[] and delete[] operators. + //! This behaviour can be changed by setting custom allocation routines. + //! Use set_allocator() function to set them. + //!

+ //! Allocations for nodes, attributes and strings are aligned at RAPIDXML_ALIGNMENT bytes. + //! This value defaults to the size of pointer on target architecture. + //!

+ //! To obtain absolutely top performance from the parser, + //! it is important that all nodes are allocated from a single, contiguous block of memory. + //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. + //! If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT + //! to obtain best wasted memory to performance compromise. + //! To do it, define their values before rapidxml.hpp file is included. + //! \param Ch Character type of created nodes. + template + class memory_pool + { + + public: + + //! \cond internal + typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory + typedef void (free_func)(void *); // Type of user-defined function used to free memory + //! \endcond + + //! Constructs empty pool with default allocator functions. + memory_pool() + : m_alloc_func(0) + , m_free_func(0) + { + init(); + } + + //! Destroys pool and frees all the memory. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Nodes allocated from the pool are no longer valid. + ~memory_pool() + { + clear(); + } + + //! Allocates a new node from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param type Type of node to create. + //! \param name Name to assign to the node, or 0 to assign no name. + //! \param value Value to assign to the node, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated node. This pointer will never be NULL. + xml_node *allocate_node(node_type type, + const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_node)); + xml_node *node = new(memory) xml_node(type); + if (name) + { + if (name_size > 0) + node->name(name, name_size); + else + node->name(name); + } + else + { + node->name(this->nullstr(), 0); + } + if (value) + { + if (value_size > 0) + node->value(value, value_size); + else + node->value(value); + } + else + { + node->value(this->nullstr(), 0); + } + return node; + } + + //! Allocates a new attribute from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param name Name to assign to the attribute, or 0 to assign no name. + //! \param value Value to assign to the attribute, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated attribute. This pointer will never be NULL. + xml_attribute *allocate_attribute(const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_attribute)); + xml_attribute *attribute = new(memory) xml_attribute; + if (name) + { + if (name_size > 0) + attribute->name(name, name_size); + else + attribute->name(name); + } + if (value) + { + if (value_size > 0) + attribute->value(value, value_size); + else + attribute->value(value); + } + return attribute; + } + + //! Allocates a char array of given size from the pool, and optionally copies a given string to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param source String to initialize the allocated memory with, or 0 to not initialize it. + //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated. + //! \return Pointer to allocated char array. This pointer will never be NULL. + template + Ch *allocate_string(const Sch *source = 0, std::size_t size = 0) + { + assert(source || size); // Either source or size (or both) must be specified + if (size == 0) + size = internal::measure(source) + 1; + Ch *result = static_cast(allocate_aligned(size * sizeof(Ch))); + if (source) + for (std::size_t i = 0; i < size; ++i) + result[i] = source[i]; + return result; + } + + Ch * nullstr() + { + if (!m_nullstr) + m_nullstr = allocate_string(""); + return m_nullstr; + } + Ch * xmlns_xml(std::size_t & xmlns_size) + { + if (!m_xmlns_xml) + m_xmlns_xml = allocate_string("http://www.w3.org/XML/1998/namespace"); + xmlns_size = internal::measure(m_xmlns_xml); + return m_xmlns_xml; + } + Ch * xmlns_xmlns(std::size_t & xmlns_size) + { + if (!m_xmlns_xmlns) + m_xmlns_xmlns = allocate_string("http://www.w3.org/2000/xmlns/"); + xmlns_size = internal::measure(m_xmlns_xmlns); + return m_xmlns_xmlns; + } + + + //! Clones an xml_node and its hierarchy of child nodes and attributes. + //! Nodes and attributes are allocated from this memory pool. + //! Names and values are not cloned, they are shared between the clone and the source. + //! Result node can be optionally specified as a second parameter, + //! in which case its contents will be replaced with cloned source node. + //! This is useful when you want to clone entire document. + //! \param source Node to clone. + //! \param result Node to put results in, or 0 to automatically allocate result node + //! \return Pointer to cloned node. This pointer will never be NULL. + xml_node *clone_node(const xml_node *source, xml_node *result = 0) + { + // Prepare result node + if (result) + { + result->remove_all_attributes(); + result->remove_all_nodes(); + result->type(source->type()); + } + else + result = allocate_node(source->type()); + + // Clone name and value + result->name(source->name(), source->name_size()); + result->value(source->value(), source->value_size()); + + // Clone child nodes and attributes + for (xml_node *child = source->first_node(); child; child = child->next_sibling()) + result->append_node(clone_node(child)); + for (xml_attribute *attr = source->first_attribute(); attr; attr = attr->next_attribute()) + result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size())); + + return result; + } + + //! Clears the pool. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Any nodes or strings allocated from the pool will no longer be valid. + void clear() + { + while (m_begin != m_static_memory) + { + char *previous_begin = reinterpret_cast
(align(m_begin))->previous_begin; + if (m_free_func) + m_free_func(m_begin); + else + delete[] m_begin; + m_begin = previous_begin; + } + init(); + } + + //! Sets or resets the user-defined memory allocation functions for the pool. + //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. + //! Allocation function must not return invalid pointer on failure. It should either throw, + //! stop the program, or use longjmp() function to pass control to other place of program. + //! If it returns invalid pointer, results are undefined. + //!

+ //! User defined allocation functions must have the following forms: + //!
+ //!
void *allocate(std::size_t size); + //!
void free(void *pointer); + //!

+ //! \param af Allocation function, or 0 to restore default function + //! \param ff Free function, or 0 to restore default function + void set_allocator(alloc_func *af, free_func *ff) + { + assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet + m_alloc_func = af; + m_free_func = ff; + } + + private: + + struct header + { + char *previous_begin; + }; + + void init() + { + m_begin = m_static_memory; + m_ptr = align(m_begin); + m_end = m_static_memory + sizeof(m_static_memory); + m_nullstr = 0; + m_xmlns_xml = 0; + m_xmlns_xmlns = 0; + } + + char *align(char *ptr) + { + std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1)); + return ptr + alignment; + } + + char *allocate_raw(std::size_t size) + { + // Allocate + void *memory; + if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[] + { + memory = m_alloc_func(size); + assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp + } + else + { + memory = new char[size]; +#ifdef RAPIDXML_NO_EXCEPTIONS + if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc + RAPIDXML_PARSE_ERROR("out of memory", 0); +#endif + } + return static_cast(memory); + } + + void *allocate_aligned(std::size_t size) + { + // Calculate aligned pointer + char *result = align(m_ptr); + + // If not enough memory left in current pool, allocate a new pool + if (result + size > m_end) + { + // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE) + std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE; + if (pool_size < size) + pool_size = size; + + // Allocate + std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation + char *raw_memory = allocate_raw(alloc_size); + + // Setup new pool in allocated memory + char *pool = align(raw_memory); + header *new_header = reinterpret_cast
(pool); + new_header->previous_begin = m_begin; + m_begin = raw_memory; + m_ptr = pool + sizeof(header); + m_end = raw_memory + alloc_size; + + // Calculate aligned pointer again using new pool + result = align(m_ptr); + } + + // Update pool and return aligned pointer + m_ptr = result + size; + return result; + } + + char *m_begin; // Start of raw memory making up current pool + char *m_ptr; // First free byte in current pool + char *m_end; // One past last available byte in current pool + char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory + alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used + free_func *m_free_func; // Free function, or 0 if default is to be used + Ch * m_nullstr; + Ch * m_xmlns_xml; + Ch * m_xmlns_xmlns; + }; + + /////////////////////////////////////////////////////////////////////////// + // XML base + + //! Base class for xml_node and xml_attribute implementing common functions: + //! name(), name_size(), value(), value_size() and parent(). + //! \param Ch Character type to use + template + class xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + // Construct a base with empty name, value and parent + xml_base() + : m_name(0) + , m_value(0) + , m_name_size(0) + , m_value_size(0) + , m_parent(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets name of the node. + //! Interpretation of name depends on type of node. + //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

+ //! Use name_size() function to determine length of the name. + //! \return Name of node, or empty string if node has no name. + Ch *name() const + { + return m_name; + } + + //! Gets size of node name, not including terminator character. + //! This function works correctly irrespective of whether name is or is not zero terminated. + //! \return Size of node name, in characters. + std::size_t name_size() const + { + return m_name ? m_name_size : 0; + } + + //! Gets value of node. + //! Interpretation of value depends on type of node. + //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

+ //! Use value_size() function to determine length of the value. + //! \return Value of node, or empty string if node has no value. + Ch *value() const + { + return m_value; + } + + //! Gets size of node value, not including terminator character. + //! This function works correctly irrespective of whether value is or is not zero terminated. + //! \return Size of node value, in characters. + std::size_t value_size() const + { + return m_value ? m_value_size : 0; + } + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets name of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

+ //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

+ //! Size of name must be specified separately, because name does not have to be zero terminated. + //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //! \param name Name of node to set. Does not have to be zero terminated. + //! \param size Size of name, in characters. This does not include zero terminator, if one is present. + void name(const Ch *name, std::size_t size) + { + m_name = const_cast(name); + m_name_size = size; + } + + //! Sets name of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t). + //! \param name Name of node to set. Must be zero terminated. + void name(const Ch *name) + { + this->name(name, internal::measure(name)); + } + + //! Sets value of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

+ //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

+ //! Size of value must be specified separately, because it does not have to be zero terminated. + //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //!

+ //! If an element has a child node of type node_data, it will take precedence over element value when printing. + //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser. + //! \param value value of node to set. Does not have to be zero terminated. + //! \param size Size of value, in characters. This does not include zero terminator, if one is present. + void value(const Ch *value, std::size_t size) + { + m_value = const_cast(value); + m_value_size = size; + } + + //! Sets value of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t). + //! \param value Vame of node to set. Must be zero terminated. + void value(const Ch *value) + { + this->value(value, internal::measure(value)); + } + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets node parent. + //! \return Pointer to parent node, or 0 if there is no parent. + xml_node *parent() const + { + return m_parent; + } + + protected: + Ch *m_name; // Name of node, or 0 if no name + Ch *m_value; // Value of node, or 0 if no value + std::size_t m_name_size; // Length of node name, or undefined of no name + std::size_t m_value_size; // Length of node value, or undefined if no value + xml_node *m_parent; // Pointer to parent node, or 0 if none + + }; + + //! Class representing attribute node of XML document. + //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). + //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. + //! Thus, this text must persist in memory for the lifetime of attribute. + //! \param Ch Character type to use. + template + class xml_attribute: public xml_base + { + + friend class xml_node; + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty attribute with the specified type. + //! Consider using memory_pool of appropriate xml_document if allocating attributes manually. + xml_attribute() : m_prev_attribute(0), m_next_attribute(0), m_xmlns(0), m_xmlns_size(0), m_local_name(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which attribute is a child. + //! \return Pointer to document that contains this attribute, or 0 if there is no parent document. + xml_document *document() const + { + if (xml_node *node = this->parent()) + { + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + else + return 0; + } + + Ch * xmlns() const + { + if (m_xmlns) return m_xmlns; + Ch * p; + Ch * name = this->name(); + for (p = name; *p && *p != ':'; ++p) + if ((p - name) >= this->name_size()) break; + if (!*p || ((p - name) >= this->name_size())) { + m_xmlns = document()->nullstr(); + m_xmlns_size = 0; + return m_xmlns; + } + xml_node * element = this->parent(); + if (element) element->xmlns_lookup(m_xmlns, m_xmlns_size, name, p - name); + return m_xmlns; + } + std::size_t xmlns_size() const + { + return this->xmlns() ? m_xmlns_size : 0; + } + //! Gets previous attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_prev_attribute : 0; + } + + //! Gets next attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_next_attribute : 0; + } + + Ch * local_name() const + { + if (m_local_name) return m_local_name; + Ch * p = this->name(); + for (; *p && *p != Ch(':'); ++p); + if (*p) + m_local_name = p + 1; + else + m_local_name = this->name(); + return m_local_name; + } + + std::size_t local_name_size() const + { + return this->name_size() - (this->local_name() - this->name()); + } + + private: + + xml_attribute *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero + xml_attribute *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero + mutable Ch * m_xmlns; + mutable std::size_t m_xmlns_size; + mutable Ch * m_local_name; // ATTN: points inside m_name. + }; + + /////////////////////////////////////////////////////////////////////////// + // XML node + + //! Class representing a node of XML document. + //! Each node may have associated name and value strings, which are available through name() and value() functions. + //! Interpretation of name and value depends on type of the node. + //! Type of node can be determined by using type() function. + //!

+ //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. + //! Thus, this text must persist in the memory for the lifetime of node. + //! \param Ch Character type to use. + template + class xml_node: public xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty node with the specified type. + //! Consider using memory_pool of appropriate document to allocate nodes manually. + //! \param type Type of node to construct. + xml_node(node_type type) + : m_prefix(0) + , m_xmlns(0) + , m_prefix_size(0) + , m_xmlns_size(0) + , m_type(type) + , m_first_node(0) + , m_last_node(0) + , m_first_attribute(0) + , m_last_attribute(0) + , m_prev_sibling(0) + , m_next_sibling(0) + , m_contents(0) + , m_contents_size(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets type of node. + //! \return Type of node. + node_type type() const + { + return m_type; + } + + void prefix(const Ch *prefix, std::size_t size) + { + m_prefix = const_cast(prefix); + m_prefix_size = size; + } + void prefix(const Ch *prefix) + { + this->prefix(prefix, internal::measure(prefix)); + } + + Ch *prefix() const + { + return m_prefix; + } + + std::size_t prefix_size() const + { + return m_prefix ? m_prefix_size : 0; + } + + void contents(Ch const * contents, std::size_t contents_size) + { + m_contents = contents; + m_contents_size = contents_size; + } + Ch const * contents() const + { + return m_contents; + } + std::size_t contents_size() const + { + return m_contents ? m_contents_size : 0; + } + + Ch *xmlns() const + { + if (m_xmlns) return m_xmlns; + xmlns_lookup(m_xmlns, m_xmlns_size, m_prefix, m_prefix_size); + return m_xmlns; + } + + void xmlns_lookup(Ch *& xmlns, size_t &xmlns_size, Ch * prefix, size_t prefix_size) const + { + Ch * freeme = 0; + Ch * attrname; + if (prefix) { + // Check if the prefix begins "xml". + if (prefix_size >= 3 + && prefix[0] == Ch('x') + && prefix[1] == Ch('m') + && prefix[2] == Ch('l')) { + if (prefix_size == 3) { + xmlns = this->document()->xmlns_xml(xmlns_size); + return; + } else if (prefix_size == 5 + && prefix[3] == Ch('n') + && prefix[4] == Ch('s')) { + xmlns = this->document()->xmlns_xmlns(xmlns_size); + return; + } + } + freeme = attrname = new Ch[prefix_size + 7]; + const char * p1="xmlns"; + while (*p1) *attrname++ = *p1++; + Ch * p = prefix; + *attrname++ = Ch(':'); + while (*p) { + *attrname++ = *p++; + if ((attrname - freeme) >= std::ptrdiff_t(prefix_size + 6)) break; + } + *attrname = Ch(0); + attrname = freeme; + } else { + freeme = attrname = new Ch[6]; + const char * p1="xmlns"; + while (*p1) *attrname++ = *p1++; + *attrname = Ch(0); + attrname = freeme; + } + for (const xml_node * node = this; + node; + node = node->parent()) { + const xml_attribute * attr = node->first_attribute(attrname); + if (attr) { + xmlns = attr->value(); + if (xmlns) { + xmlns_size = attr->value_size(); + } + break; + } + } + if (!xmlns) { + if (!prefix) { + xmlns = document()->nullstr(); + xmlns_size = 0; + } + } + if (freeme) delete[] freeme; + } + + std::size_t xmlns_size() const + { + if (m_xmlns) return m_xmlns_size; + this->xmlns(); + return m_xmlns_size; + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which node is a child. + //! \return Pointer to document that contains this node, or 0 if there is no parent document. + xml_document *document() const + { + xml_node *node = const_cast *>(this); + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + + //! Gets first child node, optionally matching node name. + //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *first_node(const Ch *name = 0, const Ch *xmlns = 0, std::size_t name_size = 0, std::size_t xmlns_size = 0, bool case_sensitive = true) const + { + if (name && !name_size) name_size = internal::measure(name); + if (xmlns && !xmlns_size) xmlns_size = internal::measure(xmlns); + if (!xmlns && name) { + // No XMLNS asked for, but a name is present. + // Assume "same XMLNS". + xmlns = this->xmlns(); + xmlns_size = this->xmlns_size(); + } + for (xml_node *child = m_first_node; child; child = child->next_sibling()) + if ((!name || internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + && (!xmlns || internal::compare(child->xmlns(), child->xmlns_size(), xmlns, xmlns_size, case_sensitive))) + return child; + return 0; + } + + //! Gets last child node, optionally matching node name. + //! Behaviour is undefined if node has no children. + //! Use first_node() to test if node has children. + //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *last_node(const Ch *name = 0, const Ch *xmlns = 0, std::size_t name_size = 0, std::size_t xmlns_size = 0, bool case_sensitive = true) const + { + assert(m_first_node); // Cannot query for last child if node has no children + if (name && !name_size) name_size = internal::measure(name); + if (xmlns && !xmlns_size) xmlns_size = internal::measure(xmlns); + if (!xmlns && name) { + // No XMLNS asked for, but a name is present. + // Assume "same XMLNS". + xmlns = this->xmlns(); + xmlns_size = this->xmlns_size(); + } + for (xml_node *child = m_last_node; child; child = child->previous_sibling()) + if ((!name || internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + && (!xmlns || internal::compare(child->xmlns(), child->xmlns_size(), xmlns, xmlns_size, case_sensitive))) + return child; + return 0; + } + + //! Gets previous sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *previous_sibling(const Ch *name = 0, const Ch *xmlns = 0, std::size_t name_size = 0, std::size_t xmlns_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + if (xmlns && !xmlns_size) xmlns_size = internal::measure(xmlns); + if (!xmlns && name) { + // No XMLNS asked for, but a name is present. + // Assume "same XMLNS". + xmlns = this->xmlns(); + xmlns_size = this->xmlns_size(); + } + for (xml_node *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling) + if ((!name || internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + && (!xmlns || internal::compare(sibling->xmlns(), sibling->xmlns_size(), xmlns, xmlns_size, case_sensitive))) + return sibling; + return 0; + } + else + return m_prev_sibling; + } + + //! Gets next sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *next_sibling(const Ch *name = 0, const Ch *xmlns = 0, std::size_t name_size = 0, std::size_t xmlns_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + if (xmlns && !xmlns_size) xmlns_size = internal::measure(xmlns); + if (!xmlns && name) { + // No XMLNS asked for, but a name is present. + // Assume "same XMLNS". + xmlns = this->xmlns(); + xmlns_size = this->xmlns_size(); + } + for (xml_node *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling) + if ((!name || internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + && (!xmlns || internal::compare(sibling->xmlns(), sibling->xmlns_size(), xmlns, xmlns_size, case_sensitive))) + return sibling; + return 0; + } + else + return m_next_sibling; + } + + //! Gets first attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute; + } + + //! Gets last attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute ? m_last_attribute : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets type of node. + //! \param type Type of node to set. + void type(node_type type) + { + m_type = type; + } + + /////////////////////////////////////////////////////////////////////////// + // Node manipulation + + //! Prepends a new child node. + //! The prepended child becomes the first child, and all existing children are moved one position back. + //! \param child Node to prepend. + void prepend_node(xml_node *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_next_sibling = m_first_node; + m_first_node->m_prev_sibling = child; + } + else + { + child->m_next_sibling = 0; + m_last_node = child; + } + m_first_node = child; + child->m_parent = this; + child->m_prev_sibling = 0; + } + + //! Appends a new child node. + //! The appended child becomes the last child. + //! \param child Node to append. + void append_node(xml_node *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_prev_sibling = m_last_node; + m_last_node->m_next_sibling = child; + } + else + { + child->m_prev_sibling = 0; + m_first_node = child; + } + m_last_node = child; + child->m_parent = this; + child->m_next_sibling = 0; + } + + //! Inserts a new child node at specified place inside the node. + //! All children after and including the specified node are moved one position back. + //! \param where Place where to insert the child, or 0 to insert at the back. + //! \param child Node to insert. + void insert_node(xml_node *where, xml_node *child) + { + assert(!where || where->parent() == this); + assert(child && !child->parent() && child->type() != node_document); + if (where == m_first_node) + prepend_node(child); + else if (where == 0) + append_node(child); + else + { + child->m_prev_sibling = where->m_prev_sibling; + child->m_next_sibling = where; + where->m_prev_sibling->m_next_sibling = child; + where->m_prev_sibling = child; + child->m_parent = this; + } + } + + //! Removes first child node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_first_node() + { + assert(first_node()); + xml_node *child = m_first_node; + m_first_node = child->m_next_sibling; + if (child->m_next_sibling) + child->m_next_sibling->m_prev_sibling = 0; + else + m_last_node = 0; + child->m_parent = 0; + } + + //! Removes last child of the node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_last_node() + { + assert(first_node()); + xml_node *child = m_last_node; + if (child->m_prev_sibling) + { + m_last_node = child->m_prev_sibling; + child->m_prev_sibling->m_next_sibling = 0; + } + else + m_first_node = 0; + child->m_parent = 0; + } + + //! Removes specified child from the node + // \param where Pointer to child to be removed. + void remove_node(xml_node *where) + { + assert(where && where->parent() == this); + assert(first_node()); + if (where == m_first_node) + remove_first_node(); + else if (where == m_last_node) + remove_last_node(); + else + { + where->m_prev_sibling->m_next_sibling = where->m_next_sibling; + where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; + where->m_parent = 0; + } + } + + //! Removes all child nodes (but not attributes). + void remove_all_nodes() + { + for (xml_node *node = first_node(); node; node = node->m_next_sibling) + node->m_parent = 0; + m_first_node = 0; + } + + //! Prepends a new attribute to the node. + //! \param attribute Attribute to prepend. + void prepend_attribute(xml_attribute *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_next_attribute = m_first_attribute; + m_first_attribute->m_prev_attribute = attribute; + } + else + { + attribute->m_next_attribute = 0; + m_last_attribute = attribute; + } + m_first_attribute = attribute; + attribute->m_parent = this; + attribute->m_prev_attribute = 0; + } + + //! Appends a new attribute to the node. + //! \param attribute Attribute to append. + void append_attribute(xml_attribute *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_prev_attribute = m_last_attribute; + m_last_attribute->m_next_attribute = attribute; + } + else + { + attribute->m_prev_attribute = 0; + m_first_attribute = attribute; + } + m_last_attribute = attribute; + attribute->m_parent = this; + attribute->m_next_attribute = 0; + } + + //! Inserts a new attribute at specified place inside the node. + //! All attributes after and including the specified attribute are moved one position back. + //! \param where Place where to insert the attribute, or 0 to insert at the back. + //! \param attribute Attribute to insert. + void insert_attribute(xml_attribute *where, xml_attribute *attribute) + { + assert(!where || where->parent() == this); + assert(attribute && !attribute->parent()); + if (where == m_first_attribute) + prepend_attribute(attribute); + else if (where == 0) + append_attribute(attribute); + else + { + attribute->m_prev_attribute = where->m_prev_attribute; + attribute->m_next_attribute = where; + where->m_prev_attribute->m_next_attribute = attribute; + where->m_prev_attribute = attribute; + attribute->m_parent = this; + } + } + + //! Removes first attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_first_attribute() + { + assert(first_attribute()); + xml_attribute *attribute = m_first_attribute; + if (attribute->m_next_attribute) + { + attribute->m_next_attribute->m_prev_attribute = 0; + } + else + m_last_attribute = 0; + attribute->m_parent = 0; + m_first_attribute = attribute->m_next_attribute; + } + + //! Removes last attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_last_attribute() + { + assert(first_attribute()); + xml_attribute *attribute = m_last_attribute; + if (attribute->m_prev_attribute) + { + attribute->m_prev_attribute->m_next_attribute = 0; + m_last_attribute = attribute->m_prev_attribute; + } + else + m_first_attribute = 0; + attribute->m_parent = 0; + } + + //! Removes specified attribute from node. + //! \param where Pointer to attribute to be removed. + void remove_attribute(xml_attribute *where) + { + assert(first_attribute() && where->parent() == this); + if (where == m_first_attribute) + remove_first_attribute(); + else if (where == m_last_attribute) + remove_last_attribute(); + else + { + where->m_prev_attribute->m_next_attribute = where->m_next_attribute; + where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; + where->m_parent = 0; + } + } + + //! Removes all attributes of node. + void remove_all_attributes() + { + for (xml_attribute *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute) + attribute->m_parent = 0; + m_first_attribute = 0; + } + + void validate() const + { + if (this->xmlns() == 0) + throw validation_error("Element XMLNS unbound"); + for (xml_node * child = this->first_node(); + child; + child = child->next_sibling()) { + child->validate(); + } + for (xml_attribute *attribute = first_attribute(); + attribute; + attribute = attribute->m_next_attribute) { + if (attribute->xmlns() == 0) + throw validation_error("Attribute XMLNS unbound"); + for (xml_attribute *otherattr = first_attribute(); + otherattr != attribute; + otherattr = otherattr->m_next_attribute) { + if (internal::compare(attribute->name(), attribute->name_size(), otherattr->name(), otherattr->name_size(), true)) { + throw validation_error("Attribute doubled"); + } + if (internal::compare(attribute->local_name(), attribute->local_name_size(), otherattr->local_name(), otherattr->local_name_size(), true) + && internal::compare(attribute->xmlns(), attribute->xmlns_size(), otherattr->xmlns(), otherattr->xmlns_size(), true)) + throw validation_error("Attribute XMLNS doubled"); + } + } + } + + private: + + /////////////////////////////////////////////////////////////////////////// + // Restrictions + + // No copying + xml_node(const xml_node &); + void operator =(const xml_node &); + + /////////////////////////////////////////////////////////////////////////// + // Data members + + // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0. + // This is required for maximum performance, as it allows the parser to omit initialization of + // unneded/redundant values. + // + // The rules are as follows: + // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively + // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage + // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage + + Ch *m_prefix; + mutable Ch *m_xmlns; // Cache + std::size_t m_prefix_size; + mutable std::size_t m_xmlns_size; + node_type m_type; // Type of node; always valid + xml_node *m_first_node; // Pointer to first child node, or 0 if none; always valid + xml_node *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero + xml_attribute *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid + xml_attribute *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero + xml_node *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + xml_node *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + Ch const *m_contents; // Pointer to original contents in buffer. + std::size_t m_contents_size; + }; + + /////////////////////////////////////////////////////////////////////////// + // XML document + + //! This class represents root of the DOM hierarchy. + //! It is also an xml_node and a memory_pool through public inheritance. + //! Use parse() function to build a DOM tree from a zero-terminated XML text string. + //! parse() function allocates memory for nodes and attributes by using functions of xml_document, + //! which are inherited from memory_pool. + //! To access root node of the document, use the document itself, as if it was an xml_node. + //! \param Ch Character type to use. + template + class xml_document: public xml_node, public memory_pool + { + + public: + + //! Constructs empty XML document + xml_document() + : xml_node(node_document) + { + } + + //! Parses zero-terminated XML string according to given flags. + //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. + //! The string must persist for the lifetime of the document. + //! In case of error, rapidxml::parse_error exception will be thrown. + //!

+ //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. + //! Make sure that data is zero-terminated. + //!

+ //! Document can be parsed into multiple times. + //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. + //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. + template + Ch * parse(Ch * text, xml_document * parent = 0) + { + assert(text); + + // Remove current contents + this->remove_all_nodes(); + this->remove_all_attributes(); + this->m_parent = parent ? parent->first_node() : 0; + + // Parse BOM, if any + parse_bom(text); + + // Parse children + while (1) + { + // Skip whitespace before node + skip(text); + if (*text == 0) + break; + + // Parse and append new child + if (*text == Ch('<')) + { + ++text; // Skip '<' + if (xml_node *node = parse_node(text)) { + this->append_node(node); + if (Flags & (parse_open_only|parse_parse_one)) { + if (node->type() == node_element) + break; + } + } + } + else + RAPIDXML_PARSE_ERROR("expected <", text); + } + if (!this->first_node()) RAPIDXML_PARSE_ERROR("no root element", text); + return text; + } + template + Ch * parse(Ch * text, xml_document & parent) + { + return parse(text, &parent); + } + + //! Clears the document by deleting all nodes and clearing the memory pool. + //! All nodes owned by document pool are destroyed. + void clear() + { + this->remove_all_nodes(); + this->remove_all_attributes(); + memory_pool::clear(); + } + + //! Terminates and/or decodes existing parsed tree, + //! optionally recursively. + template + void fixup(xml_node * element, bool recurse) + { + // Check the type. + if (element->type() == node_element) { + // Terminate name and attributes + if (!(Flags & parse_no_string_terminators)) + element->name()[element->name_size()] = 0; + for (xml_attribute *attr = element->first_attribute(); + attr; + attr = attr->next_attribute()) { + if (!(Flags & parse_no_string_terminators)) + attr->name()[attr->name_size()] = 0; + Ch * value = attr->value(); + Ch * p = value; + Ch * end; + const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes + Ch quote = value[-1]; + if (quote == Ch('\'')) + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(p); + else + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(p); + attr->value(value, end - value); + if (!(Flags & parse_no_string_terminators)) + attr->value()[attr->value_size()] = 0; + } + if (recurse) { + for (xml_node *child = element->first_node(); + child; + child = child->next_sibling()) { + this->fixup(child, true); + } + if (!(Flags & parse_no_string_terminators) && element->value()) + element->value()[element->value_size()] = 0; + } + } + } + + + void validate() const + { + for (xml_node * child = this->first_node(); + child; + child = child->next_sibling()) { + child->validate(); + } + } + + private: + + /////////////////////////////////////////////////////////////////////// + // Internal character utility functions + + // Detect whitespace character + struct whitespace_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_whitespace[static_cast(ch)]; + } + }; + + // Detect node name character + struct node_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_node_name[static_cast(ch)]; + } + }; + + // Detect element name character + struct element_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_element_name[static_cast(ch)]; + } + }; + + // Detect attribute name character + struct attribute_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_attribute_name[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) + struct text_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_no_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_with_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast(ch)]; + } + }; + + // Detect attribute value character + template + struct attribute_value_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Detect attribute value character + template + struct attribute_value_pure_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Insert coded character, using UTF8 or 8-bit ASCII + template + static void insert_coded_character(Ch *&text, unsigned long code) + { + if (Flags & parse_no_utf8) + { + // Insert 8-bit ASCII character + // Todo: possibly verify that code is less than 256 and use replacement char otherwise? + text[0] = static_cast(code); + text += 1; + } + else + { + // Insert UTF8 sequence + if (code < 0x80) // 1 byte sequence + { + text[0] = static_cast(code); + text += 1; + } + else if (code < 0x800) // 2 byte sequence + { + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xC0); + text += 2; + } + else if (code < 0x10000) // 3 byte sequence + { + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xE0); + text += 3; + } + else if (code < 0x110000) // 4 byte sequence + { + text[3] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xF0); + text += 4; + } + else // Invalid, only codes up to 0x10FFFF are allowed in Unicode + { + RAPIDXML_PARSE_ERROR("invalid numeric character entity", text); + } + } + } + + // Skip characters until predicate evaluates to true + template + static void skip(Ch *&text) + { + Ch *tmp = text; + while (StopPred::test(*tmp)) + ++tmp; + text = tmp; + } + + // Skip characters until predicate evaluates to true while doing the following: + // - replacing XML character entity references with proper characters (' & " < > &#...;) + // - condensing whitespace sequences to single space character + template + static Ch *skip_and_expand_character_refs(Ch *&text) + { + // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip + if (Flags & parse_no_entity_translation && + !(Flags & parse_normalize_whitespace) && + !(Flags & parse_trim_whitespace)) + { + skip(text); + return text; + } + + // Use simple skip until first modification is detected + skip(text); + + // Use translation skip + Ch *src = text; + Ch *dest = src; + while (StopPred::test(*src)) + { + // If entity translation is enabled + if (!(Flags & parse_no_entity_translation)) + { + // Test if replacement is needed + if (src[0] == Ch('&')) + { + switch (src[1]) + { + + // & ' + case Ch('a'): + if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) + { + *dest = Ch('&'); + ++dest; + src += 5; + continue; + } + if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';')) + { + *dest = Ch('\''); + ++dest; + src += 6; + continue; + } + break; + + // " + case Ch('q'): + if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';')) + { + *dest = Ch('"'); + ++dest; + src += 6; + continue; + } + break; + + // > + case Ch('g'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('>'); + ++dest; + src += 4; + continue; + } + break; + + // < + case Ch('l'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('<'); + ++dest; + src += 4; + continue; + } + break; + + // &#...; - assumes ASCII + case Ch('#'): + if (src[2] == Ch('x')) + { + unsigned long code = 0; + src += 3; // Skip &#x + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 16 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + else + { + unsigned long code = 0; + src += 2; // Skip &# + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 10 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + if (*src == Ch(';')) + ++src; + else + RAPIDXML_PARSE_ERROR("expected ;", src); + continue; + + // Something else + default: + // Ignore, just copy '&' verbatim + break; + + } + } + } + + // If whitespace condensing is enabled + if (Flags & parse_normalize_whitespace) + { + // Test if condensing is needed + if (whitespace_pred::test(*src)) + { + *dest = Ch(' '); ++dest; // Put single space in dest + ++src; // Skip first whitespace char + // Skip remaining whitespace chars + while (whitespace_pred::test(*src)) + ++src; + continue; + } + } + + // No replacement, only copy character + *dest++ = *src++; + + } + + // Return new end + text = src; + return dest; + + } + + /////////////////////////////////////////////////////////////////////// + // Internal parsing functions + + // Parse BOM, if any + template + void parse_bom(Ch *&text) + { + // UTF-8? + if (static_cast(text[0]) == 0xEF && + static_cast(text[1]) == 0xBB && + static_cast(text[2]) == 0xBF) + { + text += 3; // Skup utf-8 bom + } + } + + // Parse XML declaration ( + xml_node *parse_xml_declaration(Ch *&text) + { + // If parsing of declaration is disabled + if (!(Flags & parse_declaration_node)) + { + // Skip until end of declaration + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (!text[0]) RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + + // Create declaration + xml_node *declaration = this->allocate_node(node_declaration); + + // Skip whitespace before attributes or ?> + skip(text); + + // Parse declaration attributes + parse_node_attributes(text, declaration); + + // Skip ?> + if (text[0] != Ch('?') || text[1] != Ch('>')) RAPIDXML_PARSE_ERROR("expected ?>", text); + text += 2; + + return declaration; + } + + // Parse XML comment (' + return 0; // Do not produce comment node + } + + // Remember value start + Ch *value = text; + + // Skip until end of comment + while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) + { + if (!text[0]) RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create comment node + xml_node *comment = this->allocate_node(node_comment); + comment->value(value, text - value); + + // Place zero terminator after comment value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip '-->' + return comment; + } + + // Parse DOCTYPE + template + xml_node *parse_doctype(Ch *&text) + { + // Remember value start + Ch *value = text; + + // Skip to > + while (*text != Ch('>')) + { + // Determine character type + switch (*text) + { + + // If '[' encountered, scan for matching ending ']' using naive algorithm with depth + // This works for all W3C test files except for 2 most wicked + case Ch('['): + { + ++text; // Skip '[' + int depth = 1; + while (depth > 0) + { + switch (*text) + { + case Ch('['): ++depth; break; + case Ch(']'): --depth; break; + case 0: RAPIDXML_PARSE_ERROR("unexpected end of data", text); + } + ++text; + } + break; + } + + // Error on end of text + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Other character, skip it + default: + ++text; + + } + } + + // If DOCTYPE nodes enabled + if (Flags & parse_doctype_node) + { + // Create a new doctype node + xml_node *doctype = this->allocate_node(node_doctype); + doctype->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 1; // skip '>' + return doctype; + } + else + { + text += 1; // skip '>' + return 0; + } + + } + + // Parse PI + template + xml_node *parse_pi(Ch *&text) + { + // If creation of PI nodes is enabled + if (Flags & parse_pi_nodes) + { + // Create pi node + xml_node *pi = this->allocate_node(node_pi); + + // Extract PI target name + Ch *name = text; + skip(text); + if (text == name) RAPIDXML_PARSE_ERROR("expected PI target", text); + pi->name(name, text - name); + + // Skip whitespace between pi target and pi + skip(text); + + // Remember start of pi + Ch *value = text; + + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Set pi value (verbatim, no entity expansion or whitespace normalization) + pi->value(value, text - value); + + // Place zero terminator after name and value + if (!(Flags & parse_no_string_terminators)) + { + pi->name()[pi->name_size()] = Ch('\0'); + pi->value()[pi->value_size()] = Ch('\0'); + } + + text += 2; // Skip '?>' + return pi; + } + else + { + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + } + + // Parse and append data + // Return character that ends data. + // This is necessary because this character might have been overwritten by a terminating 0 + template + Ch parse_and_append_data(xml_node *node, Ch *&text, Ch *contents_start) + { + // Backup to contents start if whitespace trimming is disabled + if (!(Flags & parse_trim_whitespace)) + text = contents_start; + + // Skip until end of data + Ch *value = text, *end; + if (Flags & parse_normalize_whitespace) + end = skip_and_expand_character_refs(text); + else + end = skip_and_expand_character_refs(text); + + // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after > + if (Flags & parse_trim_whitespace) + { + if (Flags & parse_normalize_whitespace) + { + // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end + if (*(end - 1) == Ch(' ')) + --end; + } + else + { + // Backup until non-whitespace character is found + while (whitespace_pred::test(*(end - 1))) + --end; + } + } + + // If characters are still left between end and value (this test is only necessary if normalization is enabled) + // Create new data node + if (!(Flags & parse_no_data_nodes)) + { + xml_node *data = this->allocate_node(node_data); + data->value(value, end - value); + node->append_node(data); + } + + // Add data to parent node if no data exists yet + if (!(Flags & parse_no_element_values)) + if (*node->value() == Ch('\0')) + node->value(value, end - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + { + Ch ch = *text; + *end = Ch('\0'); + return ch; // Return character that ends data; this is required because zero terminator overwritten it + } + + // Return character that ends data + return *text; + } + + // Parse CDATA + template + xml_node *parse_cdata(Ch *&text) + { + // If CDATA is disabled + if (Flags & parse_no_data_nodes) + { + // Skip until end of cdata + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 3; // Skip ]]> + return 0; // Do not produce CDATA node + } + + // Skip until end of cdata + Ch *value = text; + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create new cdata node + xml_node *cdata = this->allocate_node(node_cdata); + cdata->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip ]]> + return cdata; + } + + // Parse element node + template + xml_node *parse_element(Ch *&text) + { + // Create element node + xml_node *element = this->allocate_node(node_element); + + // Extract element name + Ch *prefix = text; + skip(text); + if (text == prefix) + RAPIDXML_PARSE_ERROR("expected element name or prefix", text); + if (*text == Ch(':')) { + element->prefix(prefix, text - prefix); + ++text; + Ch *name = text; + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected element local name", text); + element->name(name, text - name); + } else { + element->name(prefix, text - prefix); + } + + // Skip whitespace between element name and attributes or > + skip(text); + + // Parse attributes, if any + parse_node_attributes(text, element); + + // Determine ending type + if (*text == Ch('>')) + { + Ch const * contents = ++text; + Ch const * contents_end = 0; + if (!(Flags & parse_open_only)) + contents_end = parse_node_contents(text, element); + std::size_t sz = contents_end - contents; + if (sz) element->contents(contents, sz); + } + else if (*text == Ch('/')) + { + ++text; + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; + if (Flags & parse_open_only) + RAPIDXML_PARSE_ERROR("open_only, but closed", text); + } + else + RAPIDXML_PARSE_ERROR("expected >", text); + + // Place zero terminator after name + if (!(Flags & parse_no_string_terminators)) { + element->name()[element->name_size()] = Ch('\0'); + if (element->prefix()) element->prefix()[element->prefix_size()] = Ch('\0'); + } + + // Return parsed element + return element; + } + + // Determine node type, and parse it + template + xml_node *parse_node(Ch *&text) + { + // Parse proper node type + switch (text[0]) + { + + // <... + default: + // Parse and append element node + return parse_element(text); + + // (text); + } + else + { + // Parse PI + return parse_pi(text); + } + + // (text); + } + break; + + // (text); + } + break; + + // (text); + } + + } // switch + + // Attempt to skip other, unrecognized node types starting with ')) + { + if (*text == 0) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + ++text; // Skip '>' + return 0; // No node recognized + + } + } + + // Parse contents of the node - children, data etc. + // Return end pointer. + template + Ch * parse_node_contents(Ch *&text, xml_node *node) + { + Ch * retval = 0; + // For all children and text + while (1) + { + // Skip whitespace between > and node contents + Ch *contents_start = text; // Store start of node contents before whitespace is skipped + skip(text); + Ch next_char = *text; + + // After data nodes, instead of continuing the loop, control jumps here. + // This is because zero termination inside parse_and_append_data() function + // would wreak havoc with the above code. + // Also, skipping whitespace after data nodes is unnecessary. + after_data_node: + + // Determine what comes next: node closing, child node, data node, or 0? + switch (next_char) + { + + // Node closing or child node + case Ch('<'): + if (text[1] == Ch('/')) + { + // Node closing + retval = text; + text += 2; // Skip '(text); + if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true)) + RAPIDXML_PARSE_ERROR("invalid closing tag name", text); + } + else + { + // No validation, just skip name + skip(text); + } + // Skip remaining whitespace after node name + skip(text); + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; // Skip '>' + if (Flags & parse_open_only) + RAPIDXML_PARSE_ERROR("Unclosed element actually closed.", text); + return retval; // Node closed, finished parsing contents + } + else + { + // Child node + ++text; // Skip '<' + if (xml_node *child = parse_node(text)) + node->append_node(child); + } + break; + + // End of data - error unless we expected this. + case Ch('\0'): + if (Flags & parse_open_only) { + return 0; + } else { + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + } + + // Data node + default: + next_char = parse_and_append_data(node, text, contents_start); + goto after_data_node; // Bypass regular processing after data nodes + + } + } + } + + // Parse XML attributes of the node + template + void parse_node_attributes(Ch *&text, xml_node *node) + { + // For all attributes + while (attribute_name_pred::test(*text)) + { + // Extract attribute name + Ch *name = text; + ++text; // Skip first character of attribute name + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected attribute name", name); + + // Create new attribute + xml_attribute *attribute = this->allocate_attribute(); + attribute->name(name, text - name); + node->append_attribute(attribute); + + // Skip whitespace after attribute name + skip(text); + + // Skip = + if (*text != Ch('=')) + RAPIDXML_PARSE_ERROR("expected =", text); + ++text; + + // Add terminating zero after name + if (!(Flags & parse_no_string_terminators)) + attribute->name()[attribute->name_size()] = 0; + + // Skip whitespace after = + skip(text); + + // Skip quote and remember if it was ' or " + Ch quote = *text; + if (quote != Ch('\'') && quote != Ch('"')) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; + + // Extract attribute value and expand char refs in it + Ch *value = text, *end; + const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes + if (quote == Ch('\'')) + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + else + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + + // Set attribute value + attribute->value(value, end - value); + + // Make sure that end quote is present + if (*text != quote) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; // Skip quote + + // Add terminating zero after value + if (!(Flags & parse_no_string_terminators)) + attribute->value()[attribute->value_size()] = 0; + + // Skip whitespace after attribute value + skip(text); + } + } + + }; + + //! \cond internal + namespace internal + { + + // Whitespace (space \n \r \t) + template + const unsigned char lookup_tables::lookup_whitespace[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F + }; + + // Element name (anything but space \n \r \t / > ? \0 and :) + template + const unsigned char lookup_tables::lookup_element_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Node name (anything but space \n \r \t / > ? \0) + template + const unsigned char lookup_tables::lookup_node_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) (anything but < \0) + template + const unsigned char lookup_tables::lookup_text[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled + // (anything but < \0 &) + template + const unsigned char lookup_tables::lookup_text_pure_no_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled + // (anything but < \0 & space \n \r \t) + template + const unsigned char lookup_tables::lookup_text_pure_with_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute name (anything but space \n \r \t / < > = ? ! \0) + template + const unsigned char lookup_tables::lookup_attribute_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote (anything but ' \0) + template + const unsigned char lookup_tables::lookup_attribute_data_1[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote that does not require processing (anything but ' \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_1_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote (anything but " \0) + template + const unsigned char lookup_tables::lookup_attribute_data_2[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote that does not require processing (anything but " \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_2_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Digits (dec and hex, 255 denotes end of numeric character reference) + template + const unsigned char lookup_tables::lookup_digits[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F + }; + + // Upper case conversion + template + const unsigned char lookup_tables::lookup_upcase[256] = + { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0 + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2 + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3 + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5 + 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7 + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8 + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9 + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F + }; + } + //! \endcond + +} + +// Undefine internal macros +#undef RAPIDXML_PARSE_ERROR + +// On MSVC, restore warnings state +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif diff --git a/original_examples/src/include/external/stb_image.h b/original_examples/src/include/external/stb_image.h new file mode 100644 index 0000000..d9c21bc --- /dev/null +++ b/original_examples/src/include/external/stb_image.h @@ -0,0 +1,7462 @@ +/* stb_image - v2.19 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine + John-Mark Allen + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan + Dave Moore Roy Eltham Hayaki Saito Nathan Reed + Won Chun Luke Graham Johan Duparc Nick Verigakis + the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar + Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex + Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 + Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw + Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus + Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo + Christian Floisand Kevin Schmidt github:darealshinji + Blazej Dariusz Roszkowski github:Michaelangel007 +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy to use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// make more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image now supports loading HDR images in general, and currently +// the Radiance .HDR file format, although the support is provided +// generically. You can still load any file through the existing interface; +// if you attempt to load an HDR file, it will be automatically remapped to +// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// By default we convert iphone-formatted PNGs back to RGB, even though +// they are internally encoded differently. You can disable this conversion +// by by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through (which +// is BGR stored in RGB). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// + + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// NOT THREADSAFE +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp, pow +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +// assume GCC or Clang on ARM targets +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + fseek((FILE*) user, n, SEEK_CUR); +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +// this is not threadsafe +static const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load = flag_true_if_should_flip; +} + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 8) { + STBI_ASSERT(ri.bits_per_channel == 16); + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + if (ri.bits_per_channel != 16) { + STBI_ASSERT(ri.bits_per_channel == 8); + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) || !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} + +static void stbi__skip(stbi__context *s, int n) +{ + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} + +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} + +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} + +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + return z + (stbi__get16le(s) << 16); +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + + +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; + default: STBI_ASSERT(0); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} + +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; + default: STBI_ASSERT(0); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (stbi_uc) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + k = stbi_lrot(j->code_buffer, n); + STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & ~sgn); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc << j->succ_low); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4]; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[288]; + stbi__uint16 value[288]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + if (z->zbuffer >= z->zbuffer_end) return 0; + return *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + STBI_ASSERT(z->size[b] == s); + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) stbi__fill_bits(a); + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (int) (z->zout - z->zout_start); + limit = old_limit = (int) (z->zout_end - z->zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) + c = stbi__zreceive(a,3)+3; + else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a,7)+11; + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + STBI_ASSERT(a->num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[288] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior; + int filter = *raw++; + + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + STBI_ASSERT(img_width_bytes <= x); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes+1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*filter_bytes; + #define STBI__CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + } + #undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define STBI__CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ + for (k=0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; + } + #undef STBI__CASE + + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride*j; // start at the beginning of the row again + for (i=0; i < x; ++i,cur+=output_bytes) { + cur[filter_bytes+1] = 255; + } + } + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16*)cur; + + for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load = 0; +static int stbi__de_iphone_flag = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth < 8) + ri->bits_per_channel = 8; + else + ri->bits_per_channel = p->depth; + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) n += 16, z >>= 16; + if (z >= 0x00100) n += 8, z >>= 8; + if (z >= 0x00010) n += 4, z >>= 4; + if (z >= 0x00004) n += 2, z >>= 2; + if (z >= 0x00002) n += 1, z >>= 1; + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v >= 0 && v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; +} stbi__bmp_data; + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - 14 - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - 14 - info.hsz) >> 2; + } + + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - 14 - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i], p1[i] = p2[i], p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + g->history = (stbi_uc *) stbi__malloc(g->w * g->h); + if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "tranparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to teh color that was there the previous frame. + memset( g->out, 0x00, 4 * g->w * g->h ); + memset( g->background, 0x00, 4 * g->w * g->h ); // state of the background (starts transparent) + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispoase of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (o == NULL) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + out = (stbi_uc*) STBI_REALLOC( out, layers * stride ); + if (delays) { + *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + stbi__rewind( s ); + if (p == NULL) + return 0; + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) *comp = info.ma ? 4 : 3; + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + (void) stbi__get32be(s); + (void) stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) +// Does not support 16-bit-per-channel + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/original_examples/src/include/external/stb_image_write.h b/original_examples/src/include/external/stb_image_write.h new file mode 100644 index 0000000..c05e958 --- /dev/null +++ b/original_examples/src/include/external/stb_image_write.h @@ -0,0 +1,1568 @@ +/* stb_image_write - v1.09 - public domain - http://nothings.org/stb/stb_image_write.h + writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 + no warranty implied; use at your own risk + + Before #including, + + #define STB_IMAGE_WRITE_IMPLEMENTATION + + in the file that you want to have the implementation. + + Will probably not work correctly with strict-aliasing optimizations. + + If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause + compilation warnings or even errors. To avoid this, also before #including, + + #define STBI_MSC_SECURE_CRT + +ABOUT: + + This header file is a library for writing images to C stdio. It could be + adapted to write to memory or a general streaming interface; let me know. + + The PNG output is not optimal; it is 20-50% larger than the file + written by a decent optimizing implementation; though providing a custom + zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. + This library is designed for source code compactness and simplicity, + not optimal image file size or run-time performance. + +BUILDING: + + You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. + You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace + malloc,realloc,free. + You can #define STBIW_MEMMOVE() to replace memmove() + You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function + for PNG compression (instead of the builtin one), it must have the following signature: + unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); + The returned data will be freed with STBIW_FREE() (free() by default), + so it must be heap allocated with STBIW_MALLOC() (malloc() by default), + +USAGE: + + There are five functions, one for each image file format: + + int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); + int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); + + void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically + + There are also five equivalent functions that use an arbitrary write function. You are + expected to open/close your file-equivalent before and after calling these: + + int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); + int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); + int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + + where the callback is: + void stbi_write_func(void *context, void *data, int size); + + You can configure it with these global variables: + int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE + int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression + int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode + + + You can define STBI_WRITE_NO_STDIO to disable the file variant of these + functions, so the library will not use stdio.h at all. However, this will + also disable HDR writing, because it requires stdio for formatted output. + + Each function returns 0 on failure and non-0 on success. + + The functions create an image file defined by the parameters. The image + is a rectangle of pixels stored from left-to-right, top-to-bottom. + Each pixel contains 'comp' channels of data stored interleaved with 8-bits + per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is + monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. + The *data pointer points to the first byte of the top-left-most pixel. + For PNG, "stride_in_bytes" is the distance in bytes from the first byte of + a row of pixels to the first byte of the next row of pixels. + + PNG creates output files with the same number of components as the input. + The BMP format expands Y to RGB in the file format and does not + output alpha. + + PNG supports writing rectangles of data even when the bytes storing rows of + data are not consecutive in memory (e.g. sub-rectangles of a larger image), + by supplying the stride between the beginning of adjacent rows. The other + formats do not. (Thus you cannot write a native-format BMP through the BMP + writer, both because it is in BGR order and because it may have padding + at the end of the line.) + + PNG allows you to set the deflate compression level by setting the global + variable 'stbi_write_png_compression_level' (it defaults to 8). + + HDR expects linear float data. Since the format is always 32-bit rgb(e) + data, alpha (if provided) is discarded, and for monochrome data it is + replicated across all three channels. + + TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed + data, set the global variable 'stbi_write_tga_with_rle' to 0. + + JPEG does ignore alpha channels in input data; quality is between 1 and 100. + Higher quality looks better but results in a bigger image. + JPEG baseline (no JPEG progressive). + +CREDITS: + + + Sean Barrett - PNG/BMP/TGA + Baldur Karlsson - HDR + Jean-Sebastien Guay - TGA monochrome + Tim Kelsey - misc enhancements + Alan Hickman - TGA RLE + Emmanuel Julien - initial file IO callback implementation + Jon Olick - original jo_jpeg.cpp code + Daniel Gibson - integrate JPEG, allow external zlib + Aarni Koskela - allow choosing PNG filter + + bugfixes: + github:Chribba + Guillaume Chereau + github:jry2 + github:romigrou + Sergio Gonzalez + Jonas Karlsson + Filip Wasil + Thatcher Ulrich + github:poppolopoppo + Patrick Boettcher + github:xeekworx + Cap Petschulat + Simon Rodriguez + Ivan Tikhonov + github:ignotion + Adam Schackart + +LICENSE + + See end of file for license information. + +*/ + +#ifndef INCLUDE_STB_IMAGE_WRITE_H +#define INCLUDE_STB_IMAGE_WRITE_H + +// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' +#ifndef STBIWDEF +#ifdef STB_IMAGE_WRITE_STATIC +#define STBIWDEF static +#else +#ifdef __cplusplus +#define STBIWDEF extern "C" +#else +#define STBIWDEF extern +#endif +#endif +#endif + +#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations +extern int stbi_write_tga_with_rle; +extern int stbi_write_png_compression_level; +extern int stbi_write_force_png_filter; +#endif + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); +#endif + +typedef void stbi_write_func(void *context, void *data, int size); + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + +STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); + +#endif//INCLUDE_STB_IMAGE_WRITE_H + +#ifdef STB_IMAGE_WRITE_IMPLEMENTATION + +#ifdef _WIN32 + #ifndef _CRT_SECURE_NO_WARNINGS + #define _CRT_SECURE_NO_WARNINGS + #endif + #ifndef _CRT_NONSTDC_NO_DEPRECATE + #define _CRT_NONSTDC_NO_DEPRECATE + #endif +#endif + +#ifndef STBI_WRITE_NO_STDIO +#include +#endif // STBI_WRITE_NO_STDIO + +#include +#include +#include +#include + +#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) +// ok +#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." +#endif + +#ifndef STBIW_MALLOC +#define STBIW_MALLOC(sz) malloc(sz) +#define STBIW_REALLOC(p,newsz) realloc(p,newsz) +#define STBIW_FREE(p) free(p) +#endif + +#ifndef STBIW_REALLOC_SIZED +#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) +#endif + + +#ifndef STBIW_MEMMOVE +#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) +#endif + + +#ifndef STBIW_ASSERT +#include +#define STBIW_ASSERT(x) assert(x) +#endif + +#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) + +#ifdef STB_IMAGE_WRITE_STATIC +static int stbi__flip_vertically_on_write=0; +static int stbi_write_png_compression_level = 8; +static int stbi_write_tga_with_rle = 1; +static int stbi_write_force_png_filter = -1; +#else +int stbi_write_png_compression_level = 8; +int stbi__flip_vertically_on_write=0; +int stbi_write_tga_with_rle = 1; +int stbi_write_force_png_filter = -1; +#endif + +STBIWDEF void stbi_flip_vertically_on_write(int flag) +{ + stbi__flip_vertically_on_write = flag; +} + +typedef struct +{ + stbi_write_func *func; + void *context; +} stbi__write_context; + +// initialize a callback-based context +static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) +{ + s->func = c; + s->context = context; +} + +#ifndef STBI_WRITE_NO_STDIO + +static void stbi__stdio_write(void *context, void *data, int size) +{ + fwrite(data,1,size,(FILE*) context); +} + +static int stbi__start_write_file(stbi__write_context *s, const char *filename) +{ + FILE *f; +#ifdef STBI_MSC_SECURE_CRT + if (fopen_s(&f, filename, "wb")) + f = NULL; +#else + f = fopen(filename, "wb"); +#endif + stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); + return f != NULL; +} + +static void stbi__end_write_file(stbi__write_context *s) +{ + fclose((FILE *)s->context); +} + +#endif // !STBI_WRITE_NO_STDIO + +typedef unsigned int stbiw_uint32; +typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; + +static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) +{ + while (*fmt) { + switch (*fmt++) { + case ' ': break; + case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); + s->func(s->context,&x,1); + break; } + case '2': { int x = va_arg(v,int); + unsigned char b[2]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x>>8); + s->func(s->context,b,2); + break; } + case '4': { stbiw_uint32 x = va_arg(v,int); + unsigned char b[4]; + b[0]=STBIW_UCHAR(x); + b[1]=STBIW_UCHAR(x>>8); + b[2]=STBIW_UCHAR(x>>16); + b[3]=STBIW_UCHAR(x>>24); + s->func(s->context,b,4); + break; } + default: + STBIW_ASSERT(0); + return; + } + } +} + +static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) +{ + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); +} + +static void stbiw__putc(stbi__write_context *s, unsigned char c) +{ + s->func(s->context, &c, 1); +} + +static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) +{ + unsigned char arr[3]; + arr[0] = a, arr[1] = b, arr[2] = c; + s->func(s->context, arr, 3); +} + +static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) +{ + unsigned char bg[3] = { 255, 0, 255}, px[3]; + int k; + + if (write_alpha < 0) + s->func(s->context, &d[comp - 1], 1); + + switch (comp) { + case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case + case 1: + if (expand_mono) + stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp + else + s->func(s->context, d, 1); // monochrome TGA + break; + case 4: + if (!write_alpha) { + // composite against pink background + for (k = 0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + s->func(s->context, &d[comp - 1], 1); +} + +static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) +{ + stbiw_uint32 zero = 0; + int i,j, j_end; + + if (y <= 0) + return; + + if (stbi__flip_vertically_on_write) + vdir *= -1; + + if (vdir < 0) + j_end = -1, j = y-1; + else + j_end = y, j = 0; + + for (; j != j_end; j += vdir) { + for (i=0; i < x; ++i) { + unsigned char *d = (unsigned char *) data + (j*x+i)*comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } + s->func(s->context, &zero, scanline_pad); + } +} + +static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) +{ + if (y < 0 || x < 0) { + return 0; + } else { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); + stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); + return 1; + } +} + +static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) +{ + int pad = (-x*3) & 3; + return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header +} + +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif //!STBI_WRITE_NO_STDIO + +static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) +{ + int has_alpha = (comp == 2 || comp == 4); + int colorbytes = has_alpha ? comp-1 : comp; + int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 + + if (y < 0 || x < 0) + return 0; + + if (!stbi_write_tga_with_rle) { + return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, + "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); + } else { + int i,j,k; + int jend, jdir; + + stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); + + if (stbi__flip_vertically_on_write) { + j = 0; + jend = y; + jdir = 1; + } else { + j = y-1; + jend = -1; + jdir = -1; + } + for (; j != jend; j += jdir) { + unsigned char *row = (unsigned char *) data + j * x * comp; + int len; + + for (i = 0; i < x; i += len) { + unsigned char *begin = row + i * comp; + int diff = 1; + len = 1; + + if (i < x - 1) { + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); + if (diff) { + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; + } else { + --len; + break; + } + } + } else { + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; + } else { + break; + } + } + } + } + + if (diff) { + unsigned char header = STBIW_UCHAR(len - 1); + s->func(s->context, &header, 1); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = STBIW_UCHAR(len - 129); + s->func(s->context, &header, 1); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } + } + } + } + return 1; +} + +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR writer +// by Baldur Karlsson + +#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) + +void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) +{ + int exponent; + float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); + + if (maxcomp < 1e-32f) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } else { + float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; + + rgbe[0] = (unsigned char)(linear[0] * normalize); + rgbe[1] = (unsigned char)(linear[1] * normalize); + rgbe[2] = (unsigned char)(linear[2] * normalize); + rgbe[3] = (unsigned char)(exponent + 128); + } +} + +void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) +{ + unsigned char lengthbyte = STBIW_UCHAR(length+128); + STBIW_ASSERT(length+128 <= 255); + s->func(s->context, &lengthbyte, 1); + s->func(s->context, &databyte, 1); +} + +void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) +{ + unsigned char lengthbyte = STBIW_UCHAR(length); + STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code + s->func(s->context, &lengthbyte, 1); + s->func(s->context, data, length); +} + +void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) +{ + unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; + unsigned char rgbe[4]; + float linear[3]; + int x; + + scanlineheader[2] = (width&0xff00)>>8; + scanlineheader[3] = (width&0x00ff); + + /* skip RLE for images too small or large */ + if (width < 8 || width >= 32768) { + for (x=0; x < width; x++) { + switch (ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + s->func(s->context, rgbe, 4); + } + } else { + int c,r; + /* encode into scratch buffer */ + for (x=0; x < width; x++) { + switch(ncomp) { + case 4: /* fallthrough */ + case 3: linear[2] = scanline[x*ncomp + 2]; + linear[1] = scanline[x*ncomp + 1]; + linear[0] = scanline[x*ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + scratch[x + width*0] = rgbe[0]; + scratch[x + width*1] = rgbe[1]; + scratch[x + width*2] = rgbe[2]; + scratch[x + width*3] = rgbe[3]; + } + + s->func(s->context, scanlineheader, 4); + + /* RLE each component separately */ + for (c=0; c < 4; c++) { + unsigned char *comp = &scratch[width*c]; + + x = 0; + while (x < width) { + // find first run + r = x; + while (r+2 < width) { + if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) + break; + ++r; + } + if (r+2 >= width) + r = width; + // dump up to first run + while (x < r) { + int len = r-x; + if (len > 128) len = 128; + stbiw__write_dump_data(s, len, &comp[x]); + x += len; + } + // if there's a run, output it + if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd + // find next byte after run + while (r < width && comp[r] == comp[x]) + ++r; + // output run up to r + while (x < r) { + int len = r-x; + if (len > 127) len = 127; + stbiw__write_run_data(s, len, comp[x]); + x += len; + } + } + } + } + } +} + +static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) +{ + if (y <= 0 || x <= 0 || data == NULL) + return 0; + else { + // Each component is stored separately. Allocate scratch space for full output scanline. + unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); + int i, len; + char buffer[128]; + char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header)-1); + +#ifdef STBI_MSC_SECURE_CRT + len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#else + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#endif + s->func(s->context, buffer, len); + + for(i=0; i < y; i++) + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)*x); + STBIW_FREE(scratch); + return 1; + } +} + +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *) data); +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif // STBI_WRITE_NO_STDIO + + +////////////////////////////////////////////////////////////////////////////// +// +// PNG writer +// + +#ifndef STBIW_ZLIB_COMPRESS +// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() +#define stbiw__sbraw(a) ((int *) (a) - 2) +#define stbiw__sbm(a) stbiw__sbraw(a)[0] +#define stbiw__sbn(a) stbiw__sbraw(a)[1] + +#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) +#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) +#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) + +#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) +#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) +#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) + +static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) +{ + int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; + void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); + STBIW_ASSERT(p); + if (p) { + if (!*arr) ((int *) p)[1] = 0; + *arr = (void *) ((int *) p + 2); + stbiw__sbm(*arr) = m; + } + return *arr; +} + +static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) +{ + while (*bitcount >= 8) { + stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; +} + +static int stbiw__zlib_bitrev(int code, int codebits) +{ + int res=0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; +} + +static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) +{ + int i; + for (i=0; i < limit && i < 258; ++i) + if (a[i] != b[i]) break; + return i; +} + +static unsigned int stbiw__zhash(unsigned char *data) +{ + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; +} + +#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) +#define stbiw__zlib_add(code,codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) +#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) +// default huffman tables +#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) +#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) +#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) +#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) +#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) +#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) + +#define stbiw__ZHASH 16384 + +#endif // STBIW_ZLIB_COMPRESS + +unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +{ +#ifdef STBIW_ZLIB_COMPRESS + // user provided a zlib compress implementation, use that + return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); +#else // use builtin + static unsigned short lengthc[] = { 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, 259 }; + static unsigned char lengtheb[]= { 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 }; + static unsigned short distc[] = { 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, 32768 }; + static unsigned char disteb[] = { 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 }; + unsigned int bitbuf=0; + int i,j, bitcount=0; + unsigned char *out = NULL; + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); + if (hash_table == NULL) + return NULL; + if (quality < 5) quality = 5; + + stbiw__sbpush(out, 0x78); // DEFLATE 32K window + stbiw__sbpush(out, 0x5e); // FLEVEL = 1 + stbiw__zlib_add(1,1); // BFINAL = 1 + stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman + + for (i=0; i < stbiw__ZHASH; ++i) + hash_table[i] = NULL; + + i=0; + while (i < data_len-3) { + // hash next 3 bytes of data to be compressed + int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32768) { // if entry lies within window + int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); + if (d >= best) best=d,bestloc=hlist[j]; + } + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { + STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); + stbiw__sbn(hash_table[h]) = quality; + } + stbiw__sbpush(hash_table[h],data+i); + + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal + h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); + hlist = hash_table[h]; + n = stbiw__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32767) { + int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } + } + } + + if (bestloc) { + int d = (int) (data+i - bestloc); // distance back + STBIW_ASSERT(d <= 32767 && best <= 258); + for (j=0; best > lengthc[j+1]-1; ++j); + stbiw__zlib_huff(j+257); + if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + for (j=0; d > distc[j+1]-1; ++j); + stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); + if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { + stbiw__zlib_huffb(data[i]); + ++i; + } + } + // write out final bytes + for (;i < data_len; ++i) + stbiw__zlib_huffb(data[i]); + stbiw__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbiw__zlib_add(0,1); + + for (i=0; i < stbiw__ZHASH; ++i) + (void) stbiw__sbfree(hash_table[i]); + STBIW_FREE(hash_table); + + { + // compute adler32 on input + unsigned int s1=1, s2=0; + int blocklen = (int) (data_len % 5552); + j=0; + while (j < data_len) { + for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1; + s1 %= 65521, s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s2)); + stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s1)); + } + *out_len = stbiw__sbn(out); + // make returned pointer freeable + STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); + return (unsigned char *) stbiw__sbraw(out); +#endif // STBIW_ZLIB_COMPRESS +} + +static unsigned int stbiw__crc32(unsigned char *buffer, int len) +{ + static unsigned int crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + unsigned int crc = ~0u; + int i; + for (i=0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; +} + +#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) +#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); +#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) + +static void stbiw__wpcrc(unsigned char **data, int len) +{ + unsigned int crc = stbiw__crc32(*data - len - 4, len+4); + stbiw__wp32(*data, crc); +} + +static unsigned char stbiw__paeth(int a, int b, int c) +{ + int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); + if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); + if (pb <= pc) return STBIW_UCHAR(b); + return STBIW_UCHAR(c); +} + +// @OPTIMIZE: provide an option that always forces left-predict or paeth predict +static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) +{ + static int mapping[] = { 0,1,2,3,4 }; + static int firstmap[] = { 0,1,0,5,6 }; + int *mymap = (y != 0) ? mapping : firstmap; + int i; + int type = mymap[filter_type]; + unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); + int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; + for (i = 0; i < n; ++i) { + switch (type) { + case 0: line_buffer[i] = z[i]; break; + case 1: line_buffer[i] = z[i]; break; + case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; + case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; + case 5: line_buffer[i] = z[i]; break; + case 6: line_buffer[i] = z[i]; break; + } + } + for (i=n; i < width*n; ++i) { + switch (type) { + case 0: line_buffer[i] = z[i]; break; + case 1: line_buffer[i] = z[i] - z[i-n]; break; + case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; + case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; + case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; + } + } +} + +unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +{ + int force_filter = stbi_write_force_png_filter; + int ctype[5] = { -1, 0, 4, 2, 6 }; + unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; + unsigned char *out,*o, *filt, *zlib; + signed char *line_buffer; + int j,zlen; + + if (stride_bytes == 0) + stride_bytes = x * n; + + if (force_filter >= 5) { + force_filter = -1; + } + + filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; + line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } + for (j=0; j < y; ++j) { + int filter_type; + if (force_filter > -1) { + filter_type = force_filter; + stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, force_filter, line_buffer); + } else { // Estimate the best filter by running through all of them: + int best_filter = 0, best_filter_val = 0x7fffffff, est, i; + for (filter_type = 0; filter_type < 5; filter_type++) { + stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, filter_type, line_buffer); + + // Estimate the entropy of the line using this filter; the less, the better. + est = 0; + for (i = 0; i < x*n; ++i) { + est += abs((signed char) line_buffer[i]); + } + if (est < best_filter_val) { + best_filter_val = est; + best_filter = filter_type; + } + } + if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it + stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, best_filter, line_buffer); + filter_type = best_filter; + } + } + // when we get here, filter_type contains the filter type, and line_buffer contains the data + filt[j*(x*n+1)] = (unsigned char) filter_type; + STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); + STBIW_FREE(filt); + if (!zlib) return 0; + + // each tag requires 12 bytes of overhead + out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); + if (!out) return 0; + *out_len = 8 + 12+13 + 12+zlen + 12; + + o=out; + STBIW_MEMMOVE(o,sig,8); o+= 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = STBIW_UCHAR(ctype[n]); + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o,13); + + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); + + stbiw__wp32(o,0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o,0); + + STBIW_ASSERT(o == out + *out_len); + + return out; +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) +{ + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; +#ifdef STBI_MSC_SECURE_CRT + if (fopen_s(&f, filename, "wb")) + f = NULL; +#else + f = fopen(filename, "wb"); +#endif + if (!f) { STBIW_FREE(png); return 0; } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; +} +#endif + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) +{ + int len; + unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; +} + + +/* *************************************************************************** + * + * JPEG writer + * + * This is based on Jon Olick's jo_jpeg.cpp: + * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html + */ + +static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, + 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; + +static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { + int bitBuf = *bitBufP, bitCnt = *bitCntP; + bitCnt += bs[1]; + bitBuf |= bs[0] << (24 - bitCnt); + while(bitCnt >= 8) { + unsigned char c = (bitBuf >> 16) & 255; + stbiw__putc(s, c); + if(c == 255) { + stbiw__putc(s, 0); + } + bitBuf <<= 8; + bitCnt -= 8; + } + *bitBufP = bitBuf; + *bitCntP = bitCnt; +} + +static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { + float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; + float z1, z2, z3, z4, z5, z11, z13; + + float tmp0 = d0 + d7; + float tmp7 = d0 - d7; + float tmp1 = d1 + d6; + float tmp6 = d1 - d6; + float tmp2 = d2 + d5; + float tmp5 = d2 - d5; + float tmp3 = d3 + d4; + float tmp4 = d3 - d4; + + // Even part + float tmp10 = tmp0 + tmp3; // phase 2 + float tmp13 = tmp0 - tmp3; + float tmp11 = tmp1 + tmp2; + float tmp12 = tmp1 - tmp2; + + d0 = tmp10 + tmp11; // phase 3 + d4 = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * 0.707106781f; // c4 + d2 = tmp13 + z1; // phase 5 + d6 = tmp13 - z1; + + // Odd part + tmp10 = tmp4 + tmp5; // phase 2 + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = (tmp10 - tmp12) * 0.382683433f; // c6 + z2 = tmp10 * 0.541196100f + z5; // c2-c6 + z4 = tmp12 * 1.306562965f + z5; // c2+c6 + z3 = tmp11 * 0.707106781f; // c4 + + z11 = tmp7 + z3; // phase 5 + z13 = tmp7 - z3; + + *d5p = z13 + z2; // phase 6 + *d3p = z13 - z2; + *d1p = z11 + z4; + *d7p = z11 - z4; + + *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; +} + +static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { + int tmp1 = val < 0 ? -val : val; + val = val < 0 ? val-1 : val; + bits[1] = 1; + while(tmp1 >>= 1) { + ++bits[1]; + } + bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { + } + // end0pos = first element in reverse order !=0 + if(end0pos == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + return DU[0]; + } + for(i = 1; i <= end0pos; ++i) { + int startpos = i; + int nrzeroes; + unsigned short bits[2]; + for (; DU[i]==0 && i<=end0pos; ++i) { + } + nrzeroes = i-startpos; + if ( nrzeroes >= 16 ) { + int lng = nrzeroes>>4; + int nrmarker; + for (nrmarker=1; nrmarker <= lng; ++nrmarker) + stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); + nrzeroes &= 15; + } + stbiw__jpg_calcBits(DU[i], bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + if(end0pos != 63) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + } + return DU[0]; +} + +static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { + // Constants that don't pollute global namespace + static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; + static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; + static const unsigned char std_ac_luminance_values[] = { + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, + 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, + 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, + 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, + 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; + static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; + static const unsigned char std_ac_chrominance_values[] = { + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, + 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, + 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, + 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, + 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, + 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + // Huffman tables + static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; + static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; + static const unsigned short YAC_HT[256][2] = { + {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const unsigned short UVAC_HT[256][2] = { + {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, + 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; + static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; + static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, + 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; + + int row, col, i, k; + float fdtbl_Y[64], fdtbl_UV[64]; + unsigned char YTable[64], UVTable[64]; + + if(!data || !width || !height || comp > 4 || comp < 1) { + return 0; + } + + quality = quality ? quality : 90; + quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + + for(i = 0; i < 64; ++i) { + int uvti, yti = (YQT[i]*quality+50)/100; + YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); + uvti = (UVQT[i]*quality+50)/100; + UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); + } + + for(row = 0, k = 0; row < 8; ++row) { + for(col = 0; col < 8; ++col, ++k) { + fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + } + } + + // Write Headers + { + static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; + static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; + const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), + 3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; + s->func(s->context, (void*)head0, sizeof(head0)); + s->func(s->context, (void*)YTable, sizeof(YTable)); + stbiw__putc(s, 1); + s->func(s->context, UVTable, sizeof(UVTable)); + s->func(s->context, (void*)head1, sizeof(head1)); + s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); + s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); + stbiw__putc(s, 0x10); // HTYACinfo + s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); + s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); + stbiw__putc(s, 1); // HTUDCinfo + s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); + stbiw__putc(s, 0x11); // HTUACinfo + s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); + s->func(s->context, (void*)head2, sizeof(head2)); + } + + // Encode 8x8 macroblocks + { + static const unsigned short fillBits[] = {0x7F, 7}; + const unsigned char *imageData = (const unsigned char *)data; + int DCY=0, DCU=0, DCV=0; + int bitBuf=0, bitCnt=0; + // comp == 2 is grey+alpha (alpha is ignored) + int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + int x, y, pos; + for(y = 0; y < height; y += 8) { + for(x = 0; x < width; x += 8) { + float YDU[64], UDU[64], VDU[64]; + for(row = y, pos = 0; row < y+8; ++row) { + for(col = x; col < x+8; ++col, ++pos) { + int p = (stbi__flip_vertically_on_write ? height-1-row : row)*width*comp + col*comp; + float r, g, b; + if(row >= height) { + p -= width*comp*(row+1 - height); + } + if(col >= width) { + p -= comp*(col+1 - width); + } + + r = imageData[p+0]; + g = imageData[p+ofsG]; + b = imageData[p+ofsB]; + YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128; + UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b; + VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b; + } + } + + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + + // Do the bit alignment of the EOI marker + stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); + } + + // EOI + stbiw__putc(s, 0xFF); + stbiw__putc(s, 0xD9); + + return 1; +} + +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); +} + + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + +#endif // STB_IMAGE_WRITE_IMPLEMENTATION + +/* Revision history + 1.09 (2018-02-11) + fix typo in zlib quality API, improve STB_I_W_STATIC in C++ + 1.08 (2018-01-29) + add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter + 1.07 (2017-07-24) + doc fix + 1.06 (2017-07-23) + writing JPEG (using Jon Olick's code) + 1.05 ??? + 1.04 (2017-03-03) + monochrome BMP expansion + 1.03 ??? + 1.02 (2016-04-02) + avoid allocating large structures on the stack + 1.01 (2016-01-16) + STBIW_REALLOC_SIZED: support allocators with no realloc support + avoid race-condition in crc initialization + minor compile issues + 1.00 (2015-09-14) + installable file IO function + 0.99 (2015-09-13) + warning fixes; TGA rle support + 0.98 (2015-04-08) + added STBIW_MALLOC, STBIW_ASSERT etc + 0.97 (2015-01-18) + fixed HDR asserts, rewrote HDR rle logic + 0.96 (2015-01-17) + add HDR output + fix monochrome BMP + 0.95 (2014-08-17) + add monochrome TGA output + 0.94 (2014-05-31) + rename private functions to avoid conflicts with stb_image.h + 0.93 (2014-05-27) + warning fixes + 0.92 (2010-08-01) + casts to unsigned char to fix warnings + 0.91 (2010-07-17) + first public release + 0.90 first internal release +*/ + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/original_examples/src/include/image.hpp b/original_examples/src/include/image.hpp new file mode 100644 index 0000000..e75b626 --- /dev/null +++ b/original_examples/src/include/image.hpp @@ -0,0 +1,43 @@ +#ifndef FAST_WFC_UTILS_IMAGE_HPP_ +#define FAST_WFC_UTILS_IMAGE_HPP_ + +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "external/stb_image.h" +#include "external/stb_image_write.h" + +#include "fastwfc/utils/array2D.hpp" +#include "color.hpp" + +/** + * Read an image. Returns nullopt if there was an error. + */ +std::optional> read_image(const std::string& file_path) noexcept { + int width; + int height; + int num_components; + unsigned char *data = stbi_load(file_path.c_str(), &width, &height, &num_components, 3); + if(data == nullptr) { + return std::nullopt; + } + + Array2D m = Array2D(height, width); + for(unsigned i = 0; i < (unsigned)height; i++) { + for(unsigned j = 0; j < (unsigned)width; j++) { + unsigned index = 3 * (i * width + j); + m.data[i * width + j] = { data[index], data[index + 1], data[index + 2] }; + } + } + + free(data); + return m; +} + +/** + * Write an image in the png format. + */ +void write_image_png(const std::string& file_path, const Array2D& m) noexcept { + stbi_write_png(file_path.c_str(), m.width, m.height, 3, (const unsigned char*)m.data.data(),0); +} + +#endif // FAST_WFC_UTILS_IMAGE_HPP_ diff --git a/original_examples/src/include/rapidxml_utils.hpp b/original_examples/src/include/rapidxml_utils.hpp new file mode 100644 index 0000000..9726158 --- /dev/null +++ b/original_examples/src/include/rapidxml_utils.hpp @@ -0,0 +1,32 @@ +#ifndef FAST_WFC_UTILS_RAPIDXML_UTILS_HPP_ +#define FAST_WFC_UTILS_RAPIDXML_UTILS_HPP_ + +#include "external/rapidxml.hpp" + +namespace rapidxml { + +/** + * Get an attribute from the xml node. + * If the attribute does not exist, then return the default value given. + */ +std::string get_attribute(xml_node<> *node, const std::string &attribute, + const std::string &default_value) noexcept { + if (node->first_attribute(attribute.c_str()) != nullptr) { + return node->first_attribute(attribute.c_str())->value(); + } else { + return default_value; + } +} + +/** + * Get an attribute from the xml node. + * If the attribute does not exist, this will result in undefined behavior. + */ +std::string get_attribute(xml_node<> *node, + const std::string &attribute) noexcept { + return node->first_attribute(attribute.c_str())->value(); +} + +} // namespace rapidxml + +#endif // FAST_WFC_UTILS_IMAGE_HPP_ diff --git a/original_examples/src/include/utils.hpp b/original_examples/src/include/utils.hpp new file mode 100644 index 0000000..f028ae8 --- /dev/null +++ b/original_examples/src/include/utils.hpp @@ -0,0 +1,23 @@ +#ifndef FAST_WFC_UTILS_UTILS_HPP_ +#define FAST_WFC_UTILS_UTILS_HPP_ + +#include +#include + +/** + * Get the directory containing the file file_path. + */ +std::string get_dir(const std::string& file_path) { + for(unsigned i = file_path.size(); i > 0; --i) { + if(file_path[i] == '/') { + return std::string(file_path.begin(), file_path.begin() + i); + } + } + if(file_path[0] == '/') { + return "/"; + } else { + return "."; + } +} + +#endif // FAST_WFC_UTILS_UTILS_HPP_ diff --git a/original_examples/src/lib/main.cpp b/original_examples/src/lib/main.cpp new file mode 100644 index 0000000..d55420a --- /dev/null +++ b/original_examples/src/lib/main.cpp @@ -0,0 +1,342 @@ +#include +#include +#include +#include +#include +#include "time.h" + +#include "fastwfc/overlapping_wfc.hpp" +#include "fastwfc/tiling_wfc.hpp" +#include "fastwfc/utils/array3D.hpp" +#include "fastwfc/wfc.hpp" +#include "external/rapidxml.hpp" +#include "image.hpp" +#include "rapidxml_utils.hpp" +#include "utils.hpp" +#include + +using namespace rapidxml; +using namespace std; + +/** + * Get a random seed. + * This function use random_device on linux, but use the C rand function for + * other targets. This is because, for instance, windows don't implement + * random_device non-deterministically. + */ +int get_random_seed() { + #ifdef __linux__ + return random_device()(); + #else + return rand(); + #endif +} + +/** + * Read the overlapping wfc problem from the xml node. + */ +void read_overlapping_instance(xml_node<> *node) { + string name = rapidxml::get_attribute(node, "name"); + unsigned N = stoi(rapidxml::get_attribute(node, "N")); + bool periodic_output = (rapidxml::get_attribute(node, "periodic", "False") == "True"); + bool periodic_input = (rapidxml::get_attribute(node, "periodicInput", "True") == "True"); + bool ground = (stoi(rapidxml::get_attribute(node, "ground", "0")) != 0); + unsigned symmetry = stoi(rapidxml::get_attribute(node, "symmetry", "8")); + unsigned screenshots = stoi(rapidxml::get_attribute(node, "screenshots", "2")); + unsigned width = stoi(rapidxml::get_attribute(node, "width", "48")); + unsigned height = stoi(rapidxml::get_attribute(node, "height", "48")); + + cout << name << " started!" << endl; + + // Stop hardcoding samples + const std::string image_path = "samples/" + name + ".png"; + std::optional> m = read_image(image_path); + if (!m.has_value()) { + throw "Error while loading " + image_path; + } + + OverlappingWFCOptions options = { periodic_input, periodic_output, height, width, symmetry, ground, N}; + + for (unsigned i = 0; i < screenshots; i++) { + for (unsigned test = 0; test < 10; test++) { + int seed = get_random_seed(); + OverlappingWFC wfc(*m, options, seed); + std::optional> success = wfc.run(); + + if (success.has_value()) { + write_image_png("results/" + name + to_string(i) + ".png", *success); + cout << name << " finished!" << endl; + break; + } else { + cout << "failed!" << endl; + } + } + } +} + +/** + * Transform a symmetry name into its Symmetry enum + */ +Symmetry to_symmetry(const string &symmetry_name) { + if (symmetry_name == "X") { + return Symmetry::X; + } + if (symmetry_name == "T") { + return Symmetry::T; + } + if (symmetry_name == "I") { + return Symmetry::I; + } + if (symmetry_name == "L") { + return Symmetry::L; + } + if (symmetry_name == "\\") { + return Symmetry::backslash; + } + if (symmetry_name == "P") { + return Symmetry::P; + } + throw symmetry_name + "is an invalid Symmetry"; +} + +/** + * Read the names of the tiles in the subset in a tiling WFC problem + */ +std::optional> read_subset_names(xml_node<> *root_node, + const string &subset) { + unordered_set subset_names; + xml_node<> *subsets_node = root_node->first_node("subsets"); + + if (!subsets_node) { + return std::nullopt; + } + + xml_node<> *subset_node = subsets_node->first_node("subset"); + while (subset_node && rapidxml::get_attribute(subset_node, "name") != subset) { + subset_node = subset_node->next_sibling("subset"); + } + + if (!subset_node) { + return std::nullopt; + } + + for (xml_node<> *node = subset_node->first_node("tile"); node; + node = node->next_sibling("tile")) { + subset_names.insert(rapidxml::get_attribute(node, "name")); + } + + return subset_names; +} + +/** + * Read all tiles for a tiling problem + */ +unordered_map> read_tiles(xml_node<> *root_node, + const string ¤t_dir, + const string &subset, + unsigned size) { + + std::optional> subset_names = read_subset_names(root_node, subset); + unordered_map> tiles; + xml_node<> *tiles_node = root_node->first_node("tiles"); + + for (xml_node<> *node = tiles_node->first_node("tile"); node; node = node->next_sibling("tile")) { + string name = rapidxml::get_attribute(node, "name"); + + if (subset_names != nullopt && + subset_names->find(name) == subset_names->end()) { + continue; + } + + Symmetry symmetry = to_symmetry(rapidxml::get_attribute(node, "symmetry", "X")); + double weight = stod(rapidxml::get_attribute(node, "weight", "1.0")); + const std::string image_path = current_dir + "/" + name + ".png"; + optional> image = read_image(image_path); + + if (image == nullopt) { + vector> images; + + for (unsigned i = 0; i < nb_of_possible_orientations(symmetry); i++) { + const std::string image_path = current_dir + "/" + name + " " + to_string(i) + ".png"; + + optional> image = read_image(image_path); + + if (image == nullopt) { + throw "Error while loading " + image_path; + } + + if ((image->width != size) || (image->height != size)) { + throw "Image " + image_path + " has wrond size"; + } + + images.push_back(*image); + } + + Tile tile = {images, symmetry, weight}; + tiles.insert({name, tile}); + } else { + if ((image->width != size) || (image->height != size)) { + throw "Image " + image_path + " has wrong size"; + } + + Tile tile(*image, symmetry, weight); + tiles.insert({name, tile}); + } + } + + return tiles; +} + +/** + * Read the neighbors constraints for a tiling problem. + * A value {t1,o1,t2,o2} means that the tile t1 with orientation o1 can be + * placed at the right of the tile t2 with orientation o2. + */ +vector> read_neighbors(xml_node<> *root_node) { + + vector> neighbors; + xml_node<> *neighbor_node = root_node->first_node("neighbors"); + + for (xml_node<> *node = neighbor_node->first_node("neighbor"); node; node = node->next_sibling("neighbor")) { + string left = rapidxml::get_attribute(node, "left"); + string::size_type left_delimiter = left.find(" "); + string left_tile = left.substr(0, left_delimiter); + unsigned left_orientation = 0; + + if (left_delimiter != string::npos) { + left_orientation = stoi(left.substr(left_delimiter, string::npos)); + } + + string right = rapidxml::get_attribute(node, "right"); + string::size_type right_delimiter = right.find(" "); + string right_tile = right.substr(0, right_delimiter); + unsigned right_orientation = 0; + + if (right_delimiter != string::npos) { + right_orientation = stoi(right.substr(right_delimiter, string::npos)); + } + + neighbors.push_back({left_tile, left_orientation, right_tile, right_orientation}); + } + + return neighbors; +} + +/** + * Read an instance of a tiling WFC problem. + */ +void read_simpletiled_instance(xml_node<> *node, const string ¤t_dir) noexcept { + string name = rapidxml::get_attribute(node, "name"); + string subset = rapidxml::get_attribute(node, "subset", "tiles"); + bool periodic_output = (rapidxml::get_attribute(node, "periodic", "False") == "True"); + unsigned width = stoi(rapidxml::get_attribute(node, "width", "48")); + unsigned height = stoi(rapidxml::get_attribute(node, "height", "48")); + + cout << name << " " << subset << " started!" << endl; + + ifstream config_file("samples/" + name + "/data.xml"); + vector buffer((istreambuf_iterator(config_file)), + istreambuf_iterator()); + buffer.push_back('\0'); + xml_document<> data_document; + data_document.parse<0>(&buffer[0]); + xml_node<> *data_root_node = data_document.first_node("set"); + unsigned size = stoi(rapidxml::get_attribute(data_root_node, "size")); + + unordered_map> tiles_map = read_tiles(data_root_node, current_dir + "/" + name, subset, size); + unordered_map tiles_id; + vector> tiles; + unsigned id = 0; + + for (pair> tile : tiles_map) { + tiles_id.insert({tile.first, id}); + tiles.push_back(tile.second); + id++; + } + + vector> neighbors = read_neighbors(data_root_node); + vector> neighbors_ids; + + for (auto neighbor : neighbors) { + const string &neighbor1 = get<0>(neighbor); + const int &orientation1 = get<1>(neighbor); + const string &neighbor2 = get<2>(neighbor); + const int &orientation2 = get<3>(neighbor); + if (tiles_id.find(neighbor1) == tiles_id.end()) { + continue; + } + if (tiles_id.find(neighbor2) == tiles_id.end()) { + continue; + } + neighbors_ids.push_back(make_tuple(tiles_id[neighbor1], orientation1,tiles_id[neighbor2], orientation2)); + } + + for (unsigned test = 0; test < 10; test++) { + int seed = get_random_seed(); + TilingWFC wfc(tiles, neighbors_ids, height, width, {periodic_output},seed); + + // For the summer tileset, place water on the borders, and land in the middle + if (name == "Summer") { + for(int i = 0; i < height; i++) { + wfc.set_tile(tiles_id["water_a"], 0, i, 0); + wfc.set_tile(tiles_id["water_a"], 0, i, width - 1); + } + for(int j = 0; j < width; j++) { + wfc.set_tile(tiles_id["water_a"], 0, 0, j); + wfc.set_tile(tiles_id["water_a"], 0, height -1, j); + } + wfc.set_tile(tiles_id["grass"], 0, width / 2, height / 2); + } + + std::optional> success = wfc.run(); + if (success.has_value()) { + write_image_png("results/" + name + "_" + subset + ".png", *success); + cout << name << " finished!" << endl; + break; + } else { + cout << "failed!" << endl; + } + } +} + +/** + * Read a configuration file containing multiple wfc problems + */ +void read_config_file(const string &config_path) noexcept { + ifstream config_file(config_path); + vector buffer((istreambuf_iterator(config_file)), + istreambuf_iterator()); + buffer.push_back('\0'); + xml_document<> document; + document.parse<0>(&buffer[0]); + + xml_node<> *root_node = document.first_node("samples"); + string dir_path = get_dir(config_path) + "/" + "samples"; + for (xml_node<> *node = root_node->first_node("overlapping"); node; + node = node->next_sibling("overlapping")) { + read_overlapping_instance(node); + } + + for (xml_node<> *node = root_node->first_node("simpletiled"); node; + node = node->next_sibling("simpletiled")) { + read_simpletiled_instance(node, dir_path); + } +} + +int main() { + + // Initialize rand for non-linux targets + #ifndef __linux__ + srand(time(nullptr)); + #endif + + std::chrono::time_point start, end; + start = std::chrono::system_clock::now(); + + read_config_file("samples.xml"); + + end = std::chrono::system_clock::now(); + int elapsed_s =std::chrono::duration_cast(end - start).count(); + int elapsed_ms =std::chrono::duration_cast(end - start).count(); + std::cout << "All samples done in " << elapsed_s << "s, " << elapsed_ms % 1000 << "ms.\n"; +}

lIS~s~{9vo``g8?l|NlzB~uYVFB0s+7R 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 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/cliffturn 2.png b/original_examples/samples/Summer/cliffturn 2.png new file mode 100644 index 0000000000000000000000000000000000000000..d37cefbbd6d16d94b2d49d1106e344597dd12d92 GIT binary patch literal 5266 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 Y0rsKQR9RBhC;$Ke07*qoM6N<$f;f{@Pyhe` literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/cliffturn 3.png b/original_examples/samples/Summer/cliffturn 3.png new file mode 100644 index 0000000000000000000000000000000000000000..ba08391314620e49869afd05a33c2c3c9e486def GIT binary patch literal 5198 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 IM6N<$f(@(!C;$Ke literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/data.xml b/original_examples/samples/Summer/data.xml new file mode 100644 index 0000000..77a55fe --- /dev/null +++ b/original_examples/samples/Summer/data.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/original_examples/samples/Summer/grass 0.png b/original_examples/samples/Summer/grass 0.png new file mode 100644 index 0000000000000000000000000000000000000000..d8cbedbe83e76cf53eebec97ea04af77fac6592b GIT binary patch literal 4094 zcmVw?pMU0uAJ}a8 z{qOndCw})ke*T%|lIs=ALI_NgAAgMg_{a0tuiV|4fBI9iT#}}&*O(@k3#Su*_ya%v z#B4^MGoRBmT(A7@N8|tg+Uh!v!!U5Y@-P4D{rRVSHlr-*I^vkGUvWL-r~he1meKcJ zQD7Jh1H-^>$7Dj&@aYq}ju6B#rb(7@IGz^^77J|KzPqC=2?BhdG^K5^EV2yO#q;Po zd>_w42y`L#dln0BZqyI=yZq(`O(RX&Y=~p(nyPGV8!??aNy7C?6j2n^HFZr8aJ^!h zoX@l^r#)?prt$h6%i{Hw^Equ>41+IUna>@=AP8_Al7ukCFenOaTOU zPTSITG!1=^ZBy518gFmv3PhHb*DJb?uH*Z-E`~u>p=o3prb$_1I(Qz#z_)K$7Q?`1 zqrPw*YZ!XZBM4Y5&@_N70Ez+; zj=a97>j(nkn423`D}b)!`5D{B_pxnE6VFp;&2u&zgy7RB>bkD$+Ho)pd>_Z*dIgw7 z7zUQbV!`2nVX)h=*>FCS=lx-#s-g(NFmO6i6ilbg z=j``H5kjzD6GgNw_xDUDcpm#bS;pW0P7oTNhh-52SQe(qWIU2p=sK=f^{;eY_51mZ zu2WU2qkZ3;&v|~PuF>cJ(a27m&-vd!v$(;s&~>tmJm zmn@^IFbul3_kDf49kL8rzC5oS2h*ggXc}}~{kiAy%P$Clu4CKm_uSuex%6ep^~%$e zFp7da$1t#M9l9h@-wp$JcXVAJhUhxmEyKX=E!!>YHH!sJ!{I;}Vw!Xv(DgmQXv8p( z=M)7&Kv6Irt8%z5n#Qm5FNC_S<&wIlssKcq;y5%7;V9G%JdeI-GGVzS&pDk6dDZhd znns=js^x84b>+hYFVAc?Xc}#c=b3qq>tb0vK2D_sR25l9Sz?;9-^nuC7T;&NB+Jls z41@RgUd-oef^5rLt!P_>pzm4S7_z{IL0K}HP*s#Aiv`1gZPRsF7ONG$4;@*?a>+2T z-#2n*5JHfMM|byekScjmd=Z zSob|YO|Nw=%fV>OW`pk&1auuQFWlYH_w+sE@pv@7b{%cYW`nNNb)+f2&)@#mXBp!$ zi-q2G-CzE~!vohVX^O5h3@n$r5M5cK>r5tWUl6jtQuq=w4 zYBrW)r$EXV>01#p{fW& z)j)B~Vo?KW%H2JNfno6a%6v|im71oNrIhI*2$;=yf5$Yrxl!6}m;`|t1dXQQy2>1z zhR3I7al`p?l_F9W?dha^@Oou5B1zD7L|IbT>QO99jYFJd<1wa5ns7KEbn03SV^vjM z$9cp1``NNE3~q1HbsiqfJZC(nD%oxuA%wKW^_n2y<%N&;_S-+GO7fgx!1K(eAx-If z%98v0e_DrWD*crMFa579a9wV1)qG8-6Vv43(Rg{`cyZ5ClXK^SPsGT(1b%rR$`O>b_6YFr8u;IF4{! zPAB@FBu z{@!I7qY-gToFqY@C`a;LU6bbuVCWf-F$`uivJB7nbX^~fux*Nh(TJNH#4yNtmKW;qY2@aDUHwJvts4hF+?69FwMW zU2mF*rze_54NhIRa%wD#zNfAULc&l%yJ;e|PQIk3;rmpTdfXsz&u5YZ!(b9In-K(* zC6ZozUnxtLm3dB@riOtKdQnJC!gbkhyUhmO`8S$|yF2!KB)2b@6ou+L2I5$$t$g9< zXC@PAFG|*b^IL3-%cYepu-hSD#`h^pB{}0Uj?442A{o!K_xrYKS_vUlMI2+>=sNn3 z|Hb8^th*>EOZgnCK#s$BjHcl@svN%0;h-j9JZ8Tq4B77yLY>2PscUqdFhrVNQSieL z(Z@$Amk?b?)7tZyEF(=>E=dxih&U$C(O3V;bSh0-`GdS_%TgXEzc38aRKdTLqPnJS zNmE>xDB|snC?X7bdm~Mev!-cCxf_PEEY%63i22;g^G+UDvQZGI(~G9z`*+^n`1A?O zVmf8Bq3=1J6jt8ex`x4GK@>3>@#TwUn&`S>>d}ag51K|9!rL385u=f^)zgWO4}yTr zhQk5Z<>rR2qiwskXm z{~h4&&b2In%SE}zKNpNL3~?M`7=+bg0d$TH4nHNtWe9|nX(nZ<&#EPmbAr00G9OxN-48>Y$2OJ5Ykas2W^ z+fvsYkC-OMBe%Bz_xF5!Fd8wPPP2^jhq5r?aX#bw>gat>mJ!E{$0P}^OAs&&NWlvN zglv>NCkTSBBMcP;zP>7)69V5S&p94B9GJ}%&22V{3@wYdHzpI62xywv@4;cUvg#V! z=H`a7R74s@ESDUQtX32ST_^PqX&|#1;&5QOBn-L6Y10rz7zW!d>6NF?UReTY8pk7` zP)-7uyzo3{xtvB34-b*tQgmJDI@C-ilj+p8EOtAxOi_&__v4WupsKjLQ?x%Cdy?-& zo+AXO6Qj_V`=RUNIM8s|=j$~O5Bv(FZOh{$n+>B8z-lE|pJBhpG|k&vsX&J3p}SOd zeLfd5H4uXD-_^1ahU6K;KvA&UaXxdokfwRpVHg;Xj|iRVl$V#R?|FZx@3~&V!1MU) zUolNqE7LFy1vrNxUDuyZXd379xvE$$>AU`NVLq3enL;zuWEdDv z6iY1@N?`j=A&}@g>I$H3nawB)s*0k3PPN`>L_ZAkIbBDR;5cgf+LkENClg*?Fbw*> z3qv^#)ndVP%JCS#zA~N421T-cnlhOXhJ1XeZBwd@T>3N(F&g3fx}2KTit`yE=vx>R z1SSbp*~&@>0mmazq#A#_?aGqxFLL)d%kVFbd&gn1(6fv@VZ9D67iFKWt0aCh;dEjc zSl@b*-5iIurEL*SLs4{X%Y4pgq(>3H4;t9SF^3-kkoWga2%f%jjnmx+LBMpXav-%hU$89RUh^cuvS?eSoTBd;k6jsV?DyUI z%%@M*m#~`3;RaGn&Y8lEh&gb4RRO(pQoeZyJZxn@EN|Qvq!8vF)Ou@5ysjOI>F? zX1&JqRPr?*vkK^()`LDFmo0lB6C6gwUU!^fbjZ*=&^8-rjLMDr<{ljz=7a z$wa-7gsm`i%95r*3YG>D2Un8v7>^ID2%w|Y{lFPLwwDnp=mPt}B*K{3KDP_%(;rwidY3LFvUSHYo zd4F$Y8u9DarfHgpNYm7|#ohg+@A>jYy)Pg^L(>phMpe~a$G2~9Z*PpJYC}y^N#lI} z%wgZkEN40+&snee{Mp)UWF}lnc#4ic;tHRrc>EEeOZ)p-(4&? zpNmOk$Qcy#Id!eP(=b#L;CkM4ii{140-2kbCPL$QWU;XJ`&!djugPfRsy*^<@wBh zPg!!gAOx37E#C=|m3@BhUtg8LBnf5Ca;en(dd2fp1fc8cJ({w_vaIcvwrOORwcBAB ziW|jjZphh|lrDta+3M+(x@NUvyHyGl1S$fT`^IEK5V-gETrNm#lAGkGN9vj=QW!27 wV>~8`RLFqiN1Bo4HQ>bp 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 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/grasscorner 1.png b/original_examples/samples/Summer/grasscorner 1.png new file mode 100644 index 0000000000000000000000000000000000000000..15e7bd01bedcef9dba2dde6e2104a3408f34efd3 GIT binary patch literal 5942 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 Y2gJuss0KRpxBvhE07*qoM6N<$g4}$Qwg3PC literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/grasscorner 2.png b/original_examples/samples/Summer/grasscorner 2.png new file mode 100644 index 0000000000000000000000000000000000000000..f8438d84b986c571d5db0759231ea6d8fd705577 GIT binary patch literal 5932 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 Ef?&>a{Qv*} literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/road 3.png b/original_examples/samples/Summer/road 3.png new file mode 100644 index 0000000000000000000000000000000000000000..f889273b311471c796642b3681be4013b3aeaeea GIT binary patch literal 5834 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 z zGVvsVECZT`Fa(l>YK>hkz0C%CJ%}PO3}6_bC}3Hb&!K;x{2vE{detwLFeia#w^LTt z{K!~!oOkY!y?!@vR@2c4C&|mXL6TtGkft6ZgRaA91UwJ*Iy8Hb=ioR%)0Z5l zC`_rQmI?JbkR+;U*&y-%x%;QT+v)!euk6}Osfg~svxnvp$?~)yZH(~bjUg1~8sR)X zAJzgCffTZ^tg5@$??u5HC&)DNukCfZ+Z_Z!KYQ?V0E}@GFc!Ii9W6CCL2Y*>pM_HX1^nI(QsI zl7Jx4nik~wWj#a@Xc}}KI1cJ{@I26Us5ij2U^2PfaUBP`T?|FBJO|s3!Vpr(eukgE zbp79n!z_(k9Z}1N2k5IR2gM>-WPtIdD2iV^`SjxSb+uZ?NeV%+G>Ov4Xm_M$yOyO1 z#(xh~6;zee_0aPGK|q#aIt7XX+Xi<7{XGZ*Fbrrmh$zY?lS?|NDliO#m;JL~T?-oJh0y$9HrgIM?d%N`vK##M)kyp<#sEf%UPm-X`08rT51BwDg0g8g<6mH$+(=@UykfaPJU^=}NAc8=eCM1O; zNSvlX5P;*r^AJU_b3^*y+T)+T`aCM@>ot%hFbuTY+#Ai6Sb1BPi!7U_X_OK#4vsz7 z5B#vx>sRW{DDdz~1p+^zC=dj6R?Y|lf&fSoq6oIO_`|Op*Y!LPSQcCtTo*VFWSMZ? z7{>uYz%so;5k@1BByb#PwZJrCp)I2bj5Tl^on?V-14)AK2NN&-_x>mUHiD{x?0f1S zTZa<8-LECFbcikvSHso9!vCsgK@ccK@nsp31R71zGA+k(PzewOu`G~fa9zN0AW4`` z*h=+;$vb*;Lm7HBG>AxHwOI|B{4dh23ld6h#*cP}R#33jn?kaSR*>G!1bKjsuek z)M^lhDM0|ofh3`x2eld?2rQS8qL8`{C~_&ux5mbG!Er#AfnnLV7X%!KJO_rklm(h3 zkfwm+plJ}tplOiA@nQiaNd^HV2{;a57_8S|n!vJPnt&ki)~Ey?*f!`oL=lX~Fc@S> z0;LiV1ehimMuehZ7!U-oT*78^`L^SL>q43&mIVj`g#t__APC_55Qczq9OOAr6f~Pa zQEwxMm?VK9@HhsN1fB;;f@1N~nY;}ZB?+PkS{*O8L=NVCiB!MUb41+iZ zo(Dy_%)zVG%PGECL<|Ec3KRth0-gts1En(l{{aydAO&XJlTZKv002ovPDHLkV1oA` B=Jfyo literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/roadturn 1.png b/original_examples/samples/Summer/roadturn 1.png new file mode 100644 index 0000000000000000000000000000000000000000..5191e19bc09837b7fad63df2322c6093f8afc059 GIT binary patch literal 5681 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 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/roadturn 3.png b/original_examples/samples/Summer/roadturn 3.png new file mode 100644 index 0000000000000000000000000000000000000000..b80c01bba17077fdc22705a8d9ac54766341c953 GIT binary patch literal 5645 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 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/watercorner 0.png b/original_examples/samples/Summer/watercorner 0.png new file mode 100644 index 0000000000000000000000000000000000000000..c629e2db48d75cd3e89404edcb36e2d5d3b9be34 GIT binary patch literal 4635 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 R#*hF2002ovPDHLkV1ho{ literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/watercorner 1.png b/original_examples/samples/Summer/watercorner 1.png new file mode 100644 index 0000000000000000000000000000000000000000..c7d57665805c9467d5173ba2c4bc6a06c5ecb25b GIT binary patch literal 4688 zcmV-W60hxvP)G}Je}?{+=1l18Yok=6~lHA7>IxX zL4d51MY7By`}`^1ISX$MuN)u&f&fke$O}f69T5^mks|Nq8N2)RTwU{=MU|0WHc-@a5PUABkxum1b5)6f3$a`WHZ{8>(e zBo#^J2&FPV{Noqq--eHY+fge?_(58BuqvhZcJjJ&nfQKQ=wB6Lp z6~{T#e{Xtr929)?mcg+9U;g^|(Hmr$AN^<+hLQ5LKmQvi{-d8xfA*DaJGC~GH77rW zRp|xE>gx~JfAgGv<7kxVznlaV|+{GGSRSmt-Yxa<2a&St=rYQ{DcC-)YC|8;(azlkINjoeCwYs=xW{ z`S*O~Cw=kYrQds_t+&UYeg0+rcwZc!qr+L3F6-(%skdFHvig>&Dp_JQu!nDNR8^H_ zwWjX(M|EA7c~%yMW?GKp4yV)nfByab-RgL#pF-omdHOr zy})shWkw^CxX^VJTOUZp#TUP#%u`vzDTD39=l4JVY@~XZ`eSn5BvIYfcR%?4=#x+W zB$J)r{@vf*y?+`E{kNZfI-TDHr(Nv(l|)sPvZ83JwtHTE_q(sW)7dn#$(38F=WxZ? z=F{IFO#bl0gObO;l*#1}jD8mZP(=Ry<9&FyntOl$ z_9}L@XqVj`kD;)N)3%E9*P5xX4$;Gsr1bR8FQlR@iXw_bBq~X`R_7d_9`7E$`ttqr zR=T`#hZD=}mh;+%`wwio|wr4OT&#N>g%TQH%eMS2IzuQSF zk}OHtez5)vNBU}g)IOf9fA6DiE-YbAKmV_P{`i!AbrNq!@+WWWb5O>KkQFIQihifI z9aC0o6uCR<_YFJrqvdKHM|oLG>P^p?jm)XO^S${_d=c!n|1`PH%bSPygZl7r*$k zKl{byxL&+`H7WF8{=9RI zzKahfr?+)6Axh|W84mG%41+M_#S0_Liqi?xq$p5|{nw-Vf0gpSR>^Zp$&fEU8Y`)J zj=Vff((32`=X2k$GhKRoRwXr%^)GCDv^rF3?Uzwn)k4voq9`3BlNB^YlToGmynIHj zG2d#ZU+1<|=RdA^g=v!{Xd2rsdCsd>P8bH~b26W!D9AFZiu|$hP88>=6y1)rm`T^y zW~Za6;X`l^@>0}7uWQ*b=-JA6C>gr=?%n2#-z*(HcWuS(_GcHf`ORfom`R-WT-|l; zZcleRT)s5iA9eOWl%A|ic`J)QP~PpU!H~^{moMcYr~ygJ(iGdq^9TY=lWrGfY~>G2 zDN@w2Ja;=`CaYBX3m`pgG z$TF1A*JfWz?t~+vt0-S4jy21JEI9RgX`Y{nFKC8a@hLQcPqH^jdKCyJj)o3 z>L@C!3L)6gl@UeEwek-r_Ks&Aj+!>V-y8DJsuL-#Z5i@qWj{Lqv_& zGzmit16d}^uq+V-l@MHAp{hg?^EvO|hnmK8N>P+W zf#=cdk!2`uv{Y1HU-ws!doL)eEdKKD;g_dma*%L`Q4p17`r!wI@4vc8!szjE{7veM ze_q^fSR4sM>Ka*Qu|Seotr(3sozOIVAIHIQR7uK?A$9}XcW4Ab?x{Pm87n}4}WzkMoS>&5?g7c5A=8Sya4*G9w-^V`epS9+#j z*QQOQKE976F&q-dXc~%wuG8;R*AxZgu~n8?p0|K?U7nxm^~iI4AJe3+TWD(|fOJg*Kif}!-)s?NuhIzfl-C-t&N@8j~ImA@f7+xQXm$tzS9K#~9~3sr3ovn=Ww z;BY|GaNR&v$#aAN&~oo!#RAJh$p3;b-*WyF_yO*RwetIgrs6;6A`qVXf&U8vy;&}`P#BsYmRfT2SdCq>% zW`k|pvfQqis$$!Ar-Q087yxXyaTK9xtk)b43zL^stQHn=_vsAd&XlPACH|czt4Ew&Udpx?Dqs7 zdCvRyBnjiOIUX|@@ci8Fwk*@@F`WuUK~)I?WSQBFs_{S>MS&!V`GV6US;lO}=|rc4 zB#FZz-fnq#NXBCx9(aCcy>9oTanO0*?)>3EugCd}ux&IGSw>Mv67nJ!f;eWsZ%5-e zI1Z|+L=m>Fxo%6unnt(FV8C)o5L87@XWjzhV$NXDsj6zbWi}(vDNEv*s^WZRzb8pB zjCMtaL!O`6tdV6L2XT8#(-K|Bb=hu;;gBrj@{+nn*HIK^GxgoO%rq&hYQHBtsxd}cBsis*KUBa$S3dLjt8yd+JLWiBpgR!`R{OB`2ud_>dmJPs=e@I1z2 zgl)Ifa&sf6DNj!bK^W4UXP640sH(0r9uxS55REd_Wyx?Th9k?e=yqAJDNA}in#pEa zJ{}WAOsCFxOdKOg3`aN)am;K+UDcX~s$!b-XV@1M1)Yv8Y@5l1P6tUyam-mm#4n!3iefp!8-Q(wKJ)4}sfae0a7;dw-1;W!M26a`7beqZ@MgMoH95Qd2moX?z2 zj7AKH?JFt@rxQiN@fb@IvWyVyc3z&7CPh<2RZ>-$CUuo-`tSrxoP4!tX7p_U|AFe%O$Ex94Dqpo+HoyHCe`Ti4c77 z!7xoD+eXva?N}^mxG@M&6dEW9Q2~llZ8p_tY$|dd1jI3?6W7=B`CK+j3iSJEnxrU| z5Ew>XmdG-OiQ^)qR_Y%f&~;3cASfgWO+&;noi2G!p0nF+J01Fc&SwS#97m30be%M1 zK4*5(lV!q?!-4zzyxXNLin64615IPU&jtg=6J@^ObfT(wddhvDvgB}}-zQCpLPo=W zUDJfa#^W}MWZT@_XyWS1RAkWr?QlR6NRnt=PMVgw&hdz@Bg>qG8$5QkJ1X-W{V+o7teczTM9 zveGoFiv6Cz=X9!;OOk}c0ZAgu7?1hxJF2QO3|yBq{r|qKL1kkRn?*aH0rH&Vkv!-A z9$BU+8lqB*f;eWq#&wBfCNqEr{&h{3Wx_C6uSgOaJZ?5@Hdq#iL#sPQfe;9Ru4_rc zW&^a$yI#}lwKgaS==H5Q#`6e6guu2@6#D(Pq&Vhu%5@zf*lx+P7HUO-rZF6Hf6wi0 zE>HdyQN(V;;*um`G$M|%?e<6ik&|Rqt;@31bsUG^eZ^piqR{OkNvzkcgVwaXX~1BB zBq0Qr)gCDXb$bA9-?v6l(^~GfZH`BTsP`wpp!El!joqzNXhh*NNkHxKB?s-g3WZw?meRWAYqDp*it%V!v2e)V_v-?&)db5q&8tiQCn+O5k=hJQ&reD^974VTUPVPXvA!WF>aY@b;yR82!930c;Bn|K}%50oWMaIq{TK@jltgd{PY z^88GaU|Ga5s>w&%eFIGc7z`*&8hIC@ zZCIXjb=7_G0$s=R+C)4UP!z2-*zel_-|HdEq$!Rg4hIy4$wc*iJdcYDlB5J|+ZqfQ zjmWc>BPd$iB$9;v9@}O-rqgNdeGt&^w+lHQGoN#J$A0fwmR4108ezzI-1^Dp?ZXh) z#W0YhHow+&)pSl#)huH$pb;hDa5$JImzM+T=6VD)l7zBEw*HhXV>oQPeSgnj(E9v- zpE#!1Yb{t5aXOW~KF33&`Es7uio)^OT6Ei{+eK06^%WsiheMl3U5Br~tmX@@uKI^V z(on#3YHYWDP3sqIo1)bNG=c7P%DV#$gCGbRe&6jl9+St%77VUSzmE_st`K?7#YF=k z*>O-iZ4PgoR9TW`+4D1w(!s0K39VQrxO ziZ~`scz9@U6byr+z%&tpG_8`P-0wM`6U{=?=yWJcl7vQvn*>*u+~0Hkl01hRU1zuB zaKLpDY07@z@~rD}bJIen;lsK{R+K!)Fk1R=G^i}mG-SCo6`fAIZgt&qU=UE2Os7~@ zOYy}&?zy61nhXZ?dR$*)TAWU;Dklj_BZr33-h(ziCeK@T&T|Z19}J>ym-87RC<;y| zESo4|zh|+)wt0GLvuUqKRkf(Pz9!4sE1Tx;72iiuh@!TDM$7vBHs?3y`u_oQgju}a S^<(h}nQW#sf&U+V=F&^0;r$y?tMG>sD1( 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 Y{{?zo*&iNAKmY&$07*qoM6N<$g7Y>Rt^fc4 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/waterside 2.png b/original_examples/samples/Summer/waterside 2.png new file mode 100644 index 0000000000000000000000000000000000000000..d7a1faf0ce7dbe199efdc55fcd677eb28da5cf2d GIT binary patch literal 4705 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 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/waterturn 0.png b/original_examples/samples/Summer/waterturn 0.png new file mode 100644 index 0000000000000000000000000000000000000000..3d3444919f06452641364a6f19d84a7f6855b461 GIT binary patch literal 5212 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 W$8paeo%`+p0000P~L} literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/waterturn 1.png b/original_examples/samples/Summer/waterturn 1.png new file mode 100644 index 0000000000000000000000000000000000000000..1f9319f4023fb63a1931b5a18f37c49b4ecdf650 GIT binary patch literal 5173 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 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/waterturn 2.png b/original_examples/samples/Summer/waterturn 2.png new file mode 100644 index 0000000000000000000000000000000000000000..baf8eae3a64281be4d8584e0beb8253bfe3b1b9f GIT binary patch literal 5133 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 literal 0 HcmV?d00001 diff --git a/original_examples/samples/Summer/waterturn 3.png b/original_examples/samples/Summer/waterturn 3.png new file mode 100644 index 0000000000000000000000000000000000000000..bf26d7c92e7d7a8102c4eee89956b9772f2fa23d GIT binary patch literal 5011 zcmV;E6Kw2>P)YNS0!QMySTLH|lGPQCk9qs; z_OE~Ud!K#u>CYefrCje-pFZ>ca5nfmMfm3O;#771RDJW0Tax100Yy&Wv$NonPnc-l z+a`tw&x&9C^0Zoxl`5rjERil3_a0R9MJWvJkk_tpeU0gqUo3bq=e*=`#@!JILoP-r ziIP}>s}P1plmGs+;!l3~m#^{eJoFB8a;{7M(JGZu{>bms@h5M3eT^H?csh5Ozr5Q=NbkzabJx+d# zJx3_Ig6+MXICc|FvSf8_MGAXxWQOC*jkWljzjo*4SGJoiF`07k)NZb~+ielK+*rpG z#2v2g;|RV;cru}wb3W#BN@hUF-5p*I?LYtB==cBNZ|o29I@qehT`RjtaD`T=-o9-n z&Ge*5EcKEdk5Nvu6u%=>Hi%P;cL9e*IN$1Mt~|A0Lv#Zp?9%dWAe*>24yi~sXs(Nafy`&S-3 zI1|D>c<|`iIiXYBe)Z)+zx?+fBp?53vKk-^`&VQXMc8t+Z?83B$rFu&up|Ku5*Coa zx+3nlhm$SQydoQW!fzu*nI&3&p_*emS)g+oCF?$`O*$*hcfb9OBAuL{53gR^m|o1H zu-L!0KN=^3tlbD)RYY;ab!fF)YB-wDaSXY^*7o!)_g&lWcu{EjT^47YK>`9A&=WKv z0N2RUM2}L_UVGhbU$tS2K$JQ)@~)a``tW8SQxH2y#pXsB_u5AXkJF`I-RLam^Phjr zum1e#)f;ZqT7mkd+gJM=D@RX{;%4iQ{?Xs-IZyxd=Zh|k7fj}?beYZcd`YWKJ0u%3 zf(o`IYb*GYmWNetvGEP9TCLUVPHWG29b8f7sr2uv=a8?oxN{5NWp!PKVYIQe({K4% zHglb@(F$ypMgjL9mT_Z#F)oG|wXU9w+1+4kLyV?q zjjq_<@~&-~!)MH(ZD|JN1=gaJVD059z9RgdjW+QHSXnO9s=li_5P>wj{(3uV*t*i5 zAGJHJESWlvGIf1)G>#grEG@nmQ7xDkIF2osE-} zXD2L{zza0FU~8>j@kjkzZ!}uI(^9kr9cT&TO10&($S_csbYkKbhll#{<7KaBd;MOT zWFH;Ws-WAd)??niA=)utoKRTmis^zUBb2URd39%aF+4jo3U*)&6X@0SyR=(GA>%2Y z%bdUPyvECK2DvLbJ?yJ5gj>t;RGWsFg+s%6q%MT`8jqUnI zCr{Gj$Mvwlhd19^d+F8NaqLb`XRcvU)A5*V>Ls^dYNpHO*;+*|7{O2@CbVOs z2y5xIS?S@qv|D7U{>j7ARXw$LU0&H2>oHAH7Nss8sNH~#6{?D=!V&a)y2$PEob3j? zS9(Q}=UMr5j#F{{TCkYUUDw^*aJq4Rdc@UTR+=2m*xx9ts$S0Zct&2Zy#@=0Z~>z^ zs$kF~3@A%HkHwOoeaRJ9cY=Af{i?lsRcv)^D9S}8@&~f6xEy0Nq2OY|$%)p67^<4d zc%0{z?*gp!SzTLmlw-86s#;sSzsuI9kb)9)Rj;fLHa3ugS&0w?U-i=n9Et1j@G&1B z0DS*%y_Uc`Z|ZjSRAd**%Tx;)f-hB|WLc3H07{}@IA%B|2G=23q(S`>v2;Jf#8J(rh*3Sav%ANs5w)uP~h~IKSkf<^Vb!Hg>Q4{_E5g8eUxA_o@BY{wP|~#8LgOiW3~Y}fcrCY_{}aGTm6sUf4|if2hT(j^h`XEVdN+T zpoH|4+}~kmQ#`T~^#I@kHsP}gj&i2s*_Vg*{8FeOGG5ai`b1;Khe87`2WeE_4xGtS;qbkbzeC{}$kI~R<@cc@ek>uR$^MiNzr~mNQ+qZdg zFpC<&ojc*mmDh7IP*P%R;R-jxZ=gX=EvKiIwbmFau=Yird~l$us`F>Z566t5*}(U3 z6aie!NK;x(_IBtGdb8PVI9ygG3c3y24Xi~Vky%bXis9DtJ&;FH%Y&AkC1HRvhTM1|~C3C+u!vEeA6IW6*|X zgY^}nkl}<6KP62$Ixc5VK8??Q-mNc{9~&D~IaxxU3ZmUT@LoO252kdUqik(QM z(df?`X6fQchB0`MT%6t&Sxxm8&y*V)~o*(5J$w`qhZMchOPdTka!5%kx4{3R~m&3P3953Sn%i0k9TFASJVDIa`oH7dma~ zn#+s^eC;~7ZpEJG)m05F=SjOIq$7)53yCpkjS$o|p2td;%L%%o6ybT}>(k!v3|7|i z&Pv{F7)MY+YV53FmSeTdH1h?3kbh1iGRuv6fDUW&?z@Vef*M<3?zkt6{(6cYG0mgi@1K z%yK4)w9gfOm@9$&N}!FwbSRnSkoorzeP=bml0RV(tEj_|+*VbPkpB+b+}w#W;P zPU&~+(U^Hj!^QWo0>@#cL%YG1Ej+gzot-Y1b4Swe^RNHaKltbuA3eBtxw+{bo#^Kt zCP_#$>KaE7Mqmj8gmjK)gG{YgH@=tm-y-M+8++mQRygQe=@vD$q)3ZwnwDt}M#c^H zcj6((fBTN<-SXD<{GDxobH!`>o`>szFX+mJzo?_u()N~^lm)|DvX z_&(z?QKUcr^wH@#{#Pah*xh7%EBMjf{Ga{ZH~!u4{b3L`5GsKP{^cM4;|E`|{hTB< z-GE$hF+?g#i{#*a7*}SB#VqN}ZO~X*b5~cx)sAqLaB)K1d0kD@Vw%^5mab!v z&Y;g^!lN&l&Z#v`k2E8M*Ck`VFVM zse*21Z>CmgT!hTr`ou2+uS98`n_^Be)hudVmvgD5R26ZP)AN?{u%ly#&1xNwjAt~byy^ht})MzfIusB1WoXu2OEefoMVQNLdA25mLV_pMFAR{+G1Sf z#YJ9^viT&Nr@Az)+r8!E(q5$FpPLU{7H?@scCW774pbn!ufAz_dIN1uydl7uNvd0tG@BFU*VOFN<+n&X;A9YN;s&rHghE9@0npC>IQ6O;S)Th%@SvS;erT z5-3IN5(pL*CAbcKMN*N~0HcybBOT}Nr$0QMa=y-uE~^e%Nl}rMjFzN=>6CWt&Mp&C z=T({)i*CLgP-#ky0jseZVK5d)AV9g#37(}PwPY1bjkHKhZMifckRafsB$BuaZOAl< dMhR5?{{cnZM)4z>?Z*HB002ovPDHLkV1mEw^YH)x literal 0 HcmV?d00001 diff --git a/original_examples/samples/Town.png b/original_examples/samples/Town.png new file mode 100644 index 0000000000000000000000000000000000000000..925de00c01cb18a34746b4e51a8fc302828b5137 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&k#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DinK$vl=HlH+5Fx%6`F+?Lc`O2Dv|K}Un*0FAKj^yEqdR^}n zDR6*gsUd@h;;tlvhFc8B75@F7T$3ObDbr?{<50$D*07LqwebW7KmWzqEuDrmdKI;Vst E0HMx6CjbBd literal 0 HcmV?d00001 diff --git a/original_examples/samples/Trick Knot.png b/original_examples/samples/Trick Knot.png new file mode 100644 index 0000000000000000000000000000000000000000..eb9c6e6e137106a214c2026065ae77e44a4324aa GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^f*{Pn1SGfcUswyII14-?iy0WWg+Q3`(%rg0K*3^9 z7sn8diF+q`^Bqv&aQXS=pZT%E#GtKxN6IcnNezQzpiR^CeV5YPgg&ebxsLQ0KEf9anMpkTbG zi(`n!#H|w@g$^iiFe}$jaet(4E0P{{WQ)wK$vkgV6h3U1%D-LpLj1tIr9}sp|6bK@ zTr_{fgoVrveCqn_H}5)6THtmkn6uEHNp){*=ILq7FZpE{>zY&8>zY4ZO7)#JRV4e$ TkuSnPs~9|8{an^LB{Ts5)m%Es literal 0 HcmV?d00001 diff --git a/original_examples/samples/Water.png b/original_examples/samples/Water.png new file mode 100644 index 0000000000000000000000000000000000000000..9af51fceef5334cadd2459ec8dd07c038069054b GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9GGLLkg|>2BR0prE^_ zi(`n!#N?C%?Eel+^zh8kc~oL#pj6y(v42_9hBOzopr0ADpOlmGw# literal 0 HcmV?d00001 diff --git a/original_examples/src/include/color.hpp b/original_examples/src/include/color.hpp new file mode 100644 index 0000000..99efa9b --- /dev/null +++ b/original_examples/src/include/color.hpp @@ -0,0 +1,32 @@ +#ifndef FAST_WFC_UTILS_COLOR_HPP_ +#define FAST_WFC_UTILS_COLOR_HPP_ + +#include + +/** + * Represent a 24-bit rgb color. + */ +struct Color { + unsigned char r, g, b; + + bool operator==(const Color &c) const noexcept { + return r == c.r && g == c.g && b == c.b; + } + + bool operator!=(const Color &c) const noexcept { return !(c == *this); } +}; + +/** + * Hash function for color. + */ +namespace std { +template <> class hash { +public: + size_t operator()(const Color &c) const { + return (size_t)c.r + (size_t)256 * (size_t)c.g + + (size_t)256 * (size_t)256 * (size_t)c.b; + } +}; +} // namespace std + +#endif // FAST_WFC_UTILS_COLOR_HPP_ diff --git a/original_examples/src/include/external/rapidxml.hpp b/original_examples/src/include/external/rapidxml.hpp new file mode 100644 index 0000000..2c0bc72 --- /dev/null +++ b/original_examples/src/include/external/rapidxml.hpp @@ -0,0 +1,2969 @@ +#ifndef RAPIDXML_HPP_INCLUDED +#define RAPIDXML_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation + +// If standard library is disabled, user must provide implementations of required functions and typedefs +#if !defined(RAPIDXML_NO_STDLIB) + #include // For std::size_t + #include // For assert + #include // For placement new +#endif + +// On MSVC, disable "conditional expression is constant" warning (level 4). +// This warning is almost impossible to avoid with certain types of templated code +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) // Conditional expression is constant +#endif + +/////////////////////////////////////////////////////////////////////////// +// RAPIDXML_PARSE_ERROR + +#if defined(RAPIDXML_NO_EXCEPTIONS) + +#define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); } +#define RAPIDXML_EOF_ERROR(what, where) { parse_error_handler(what, where); assert(0); } + +namespace rapidxml +{ + //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, + //! this function is called to notify user about the error. + //! It must be defined by the user. + //!

+ //! This function cannot return. If it does, the results are undefined. + //!

+ //! A very simple definition might look like that: + //!